Skip to content

Commit 4686837

Browse files
Merge branch 'main' into feature/select_records
2 parents 83d45db + 42093d7 commit 4686837

10 files changed

Lines changed: 684 additions & 25 deletions

File tree

cumulusci/__about__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "3.92.0"
1+
__version__ = "3.93.0"

cumulusci/cumulusci.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ tasks:
8181
description: Waits on a batch apex or queueable apex job to finish.
8282
class_path: cumulusci.tasks.apex.batch.BatchApexWait
8383
group: Salesforce
84+
check_components:
85+
description: "Check if common components exist in the target org based on provided deploy paths or those from a plan/flow."
86+
class_path: cumulusci.tasks.salesforce.check_components.CheckComponents
87+
group: Salesforce Preflight Checks
8488
check_dataset_load:
8589
description: Runs as a preflight check to determine whether dataset can be loaded successfully.
8690
class_path: cumulusci.tasks.preflight.dataset_load.LoadDataSetCheck
@@ -1496,7 +1500,7 @@ project:
14961500
namespace:
14971501
install_class:
14981502
uninstall_class:
1499-
api_version: "61.0"
1503+
api_version: "62.0"
15001504
git:
15011505
default_branch: master
15021506
prefix_feature: feature/

cumulusci/tasks/metadata/package.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import urllib.parse
55
from logging import Logger, getLogger
66
from pathlib import Path
7+
from typing import Dict, List
78

89
import yaml
910

@@ -40,6 +41,28 @@ def metadata_sort_key_section(name):
4041
return key
4142

4243

44+
def process_common_components(response_messages: List, components: Dict):
45+
"""Compare compoents in the api responce object with list of components and return common common components"""
46+
if not response_messages or not components:
47+
return components
48+
49+
for message in response_messages:
50+
message_list = message.firstChild.nextSibling.firstChild.nodeValue.split("'")
51+
if len(message_list) > 1:
52+
component_type = message_list[1]
53+
message_txt = message_list[2]
54+
55+
if "is not available in this organization" in message_txt:
56+
del components[component_type]
57+
else:
58+
component_name = message_list[3]
59+
if component_name in components[component_type]:
60+
components[component_type].remove(component_name)
61+
if len(components[component_type]) == 0:
62+
del components[component_type]
63+
return components
64+
65+
4366
class MetadataParserMissingError(Exception):
4467
pass
4568

cumulusci/tasks/metadata/tests/test_package.py

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from unittest import mock
33

44
import pytest
5+
from defusedxml.minidom import parseString
56

67
from cumulusci.core.config import (
78
BaseProjectConfig,
@@ -27,6 +28,7 @@
2728
RecordTypeParser,
2829
UpdatePackageXml,
2930
metadata_sort_key,
31+
process_common_components,
3032
)
3133
from cumulusci.utils import temporary_dir, touch
3234

@@ -398,3 +400,77 @@ def test_run_task(self):
398400
with open(output_path, "r") as f:
399401
result = f.read()
400402
assert expected == result
403+
404+
405+
class TestProcessComponents:
406+
response = """<?xml version="1.0" encoding="UTF-8"?>
407+
<soapenv:Envelope
408+
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
409+
xmlns="http://soap.sforce.com/2006/04/metadata">
410+
<soapenv:Body> <checkRetrieveStatusResponse>
411+
<result>
412+
<done>true</done>
413+
<fileProperties>
414+
<createdById>0058N000006PycGQAS</createdById>
415+
<createdByName>User User</createdByName>
416+
<createdDate>2024-10-08T22:54:34.372Z</createdDate>
417+
<fileName>unpackaged/labels/CustomLabels.labels</fileName>
418+
<fullName>CustomLabels</fullName>
419+
<id>000000000000000AAA</id>
420+
<lastModifiedById>0058N000006PycGQAS</lastModifiedById>
421+
<lastModifiedByName>User User</lastModifiedByName>
422+
<lastModifiedDate>2024-10-08T22:54:34.372Z</lastModifiedDate>
423+
<type>CustomLabels</type>
424+
</fileProperties>
425+
<id>09S8N000002vlujUAA</id>
426+
<messages>
427+
<problem>Entity of type 'ApexClass' 'TestClass' cannot be found</problem>
428+
<fileName>unpackaged/package.xml</fileName>
429+
</messages>
430+
<messages>
431+
<problem>Entity of type 'CustomObject' 'TestObject' cannot be found</problem>
432+
<fileName>unpackaged/package.xml</fileName>
433+
</messages>
434+
<messages>
435+
<problem>Entity of type 'CustomObject' 'AnotherObject' cannot be found</problem>
436+
<fileName>unpackaged/package.xml</fileName>
437+
</messages>
438+
</result></checkRetrieveStatusResponse></soapenv:Body></soapenv:Envelope>
439+
"""
440+
441+
def test_process_common_components(self):
442+
443+
response_messages = parseString(self.response).getElementsByTagName("messages")
444+
445+
components = {
446+
"ApexClass": {"TestClass", "AnotherClass"},
447+
"CustomObject": {"TestObject", "AnotherObject"},
448+
}
449+
450+
result = process_common_components(response_messages, components)
451+
452+
expected_components = {
453+
"ApexClass": {"AnotherClass"},
454+
}
455+
456+
assert result == expected_components
457+
assert "ApexClass" in result
458+
assert "AnotherClass" in result["ApexClass"]
459+
assert "TestClass" not in result["ApexClass"]
460+
assert "CustomObject" not in result
461+
462+
def test_process_common_components_no_response_messages(self):
463+
components = {
464+
"ApexClass": {"TestClass", "AnotherClass"},
465+
"CustomObject": {"TestObject", "AnotherObject"},
466+
}
467+
468+
result = process_common_components([], components)
469+
470+
# If there are no response messages, the components list should remain unchanged
471+
assert result == components
472+
473+
def test_process_common_components_no_components(self):
474+
response_messages = parseString(self.response).getElementsByTagName("messages")
475+
result = process_common_components(response_messages, {})
476+
assert result == {}

cumulusci/tasks/salesforce/Deploy.py

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
from cumulusci.salesforce_api.metadata import ApiDeploy, ApiRetrieveUnpackaged
1717
from cumulusci.salesforce_api.package_zip import MetadataPackageZipBuilder
1818
from cumulusci.salesforce_api.rest_deploy import RestDeploy
19+
from cumulusci.tasks.metadata.package import process_common_components
1920
from cumulusci.tasks.salesforce.BaseSalesforceMetadataApiTask import (
2021
BaseSalesforceMetadataApiTask,
2122
)
@@ -169,38 +170,21 @@ def _create_api_object(self, package_xml, api_version):
169170
return api_retrieve_unpackaged_object
170171

171172
def _collision_check(self, src_path):
172-
xml_map = {}
173173
is_collision = False
174174
package_xml = open(f"{src_path}/package.xml", "r")
175175
source_xml_tree = metadata_tree.parse(f"{src_path}/package.xml")
176176

177-
for type in source_xml_tree.types:
178-
members = []
179-
try:
180-
for member in type.members:
181-
members.append(member.text)
182-
except AttributeError: # Exception if there are no members for a type
183-
pass
184-
xml_map[type["name"].text] = members
185-
186177
api_retrieve_unpackaged_response = self._create_api_object(
187178
package_xml.read(), source_xml_tree.version.text
188179
)
189180

181+
xml_map = metadata_tree.parse_package_xml_types("name", source_xml_tree)
182+
190183
messages = parseString(
191184
api_retrieve_unpackaged_response._get_response().content
192185
).getElementsByTagName("messages")
193186

194-
for i in range(len(messages)):
195-
# print(messages[i])
196-
message_list = messages[
197-
i
198-
].firstChild.nextSibling.firstChild.nodeValue.split("'")
199-
200-
if message_list[3] in xml_map[message_list[1]]:
201-
xml_map[message_list[1]].remove(message_list[3])
202-
if len(xml_map[message_list[1]]) == 0:
203-
del xml_map[message_list[1]]
187+
process_common_components(messages, xml_map)
204188

205189
for type, api_names in xml_map.items():
206190
if len(api_names) != 0:

0 commit comments

Comments
 (0)