Skip to content

Commit

Permalink
list_components changed
Browse files Browse the repository at this point in the history
  • Loading branch information
lakshmi2506 committed Jan 8, 2024
1 parent 914e282 commit 78ab6ab
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 60 deletions.
2 changes: 1 addition & 1 deletion cumulusci/cumulusci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,7 @@ tasks:
class_path: cumulusci.tasks.util.ListMetadataTypes
group: Salesforce Metadata
list_nonsource_trackable_components:
description: List the components of the non source trackable components
description: List the components of non source trackable Metadata types.
class_path: cumulusci.tasks.salesforce.nonsourcetracking.ListComponents
group: Salesforce Metadata
list_nonsource_trackable_metadatatypes:
Expand Down
91 changes: 47 additions & 44 deletions cumulusci/tasks/salesforce/nonsourcetracking.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@
import sarge

from cumulusci.core.config import TaskConfig
from cumulusci.core.exceptions import CumulusCIException, SfdxOrgException
from cumulusci.core.exceptions import (
CumulusCIException,
SfdxOrgException,
TaskOptionsError,
)
from cumulusci.core.sfdx import sfdx
from cumulusci.core.utils import process_list_arg
from cumulusci.tasks.salesforce import (
Expand Down Expand Up @@ -34,6 +38,8 @@ def _init_task(self):
] = self.project_config.project__package__api_version

def get_types_details(self, api_version):
# The Metadata coverage report: https://developer.salesforce.com/docs/metadata-coverage/{version} is created from
# the below URL. (So the api versions are allowed based on those report ranges)
url = f"https://dx-extended-coverage.my.salesforce-sites.com/services/apexrest/report?version={api_version}"
response = requests.get(url)
if response.status_code == 200:
Expand Down Expand Up @@ -85,35 +91,21 @@ class ListComponents(BaseSalesforceApiTask):
"api_version": {
"description": "Override the API version used to list metadatatypes",
},
"include": {
"description": "A comma-separated list of strings. "
"Components will be included if one of these strings "
"is part of either the metadata type or name. "
"Example: ``-o include CustomField,Admin`` matches both "
"``CustomField: Favorite_Color__c`` and ``Profile: Admin``"
},
"types": {
"description": "A comma-separated list of metadata types to include."
},
"exclude": {"description": "Exclude components matching this string."},
"metadata_types": {"description": "A comma-separated list of metadata types."},
}

def _init_task(self):
super()._init_task()

def _init_options(self, kwargs):
super(ListComponents, self)._init_options(kwargs)
if "api_version" not in self.options:
self.options[
"api_version"
] = self.project_config.project__package__api_version

def _init_options(self, kwargs):
super(ListComponents, self)._init_options(kwargs)
self.options["include"] = process_list_arg(self.options.get("include", [])) + [
f"{mdtype}:" for mdtype in process_list_arg(self.options.get("types", []))
]
self.options["exclude"] = process_list_arg(self.options.get("exclude", []))
self._include = self.options["include"]
self._exclude = self.options["exclude"]
self._exclude.extend(self.project_config.project__source__ignore or [])
self.options["metadata_types"] = process_list_arg(
self.options.get("metadata_types", [])
)

def _get_components(self):
task_config = TaskConfig(
Expand All @@ -124,8 +116,14 @@ def _get_components(self):
project_config=self.project_config,
task_config=task_config,
)._run_task()
if not self.options["metadata_types"]:
self.options["metadata_types"] = metadata_types
else:
for md_type in self.options["metadata_types"]:
if md_type not in metadata_types:
raise TaskOptionsError(f"Invalid metadata type: {md_type}")
list_components = []
for md_type in metadata_types:
for md_type in self.options["metadata_types"]:
p: sarge.Command = sfdx(
"force:mdapi:listmetadata",
access_token=self.org_config.access_token,
Expand Down Expand Up @@ -153,29 +151,21 @@ def _get_components(self):
change_dict = {
"MemberType": md_type,
"MemberName": cmp["fullName"],
"lastModifiedByName": cmp["lastModifiedByName"],
"lastModifiedDate": cmp["lastModifiedDate"],
}
if change_dict not in list_components:
list_components.append(change_dict)

return list_components

def _run_task(self):
changes = self._get_components()
if changes:
self.logger.info(
f"Found {len(changes)} non source trackable components in the org."
)
else:
self.logger.info("Found no non source trackable components.")

filtered, ignored = ListChanges._filter_changes(self, changes)
if ignored:
self.logger.info(f"Ignored {len(ignored)} components in the org.")
self.logger.info(f"{len(filtered)} remaining components after filtering.")

for change in filtered:
self.return_values = self._get_components()
self.logger.info(
f"Found {len(self.return_values)} non source trackable components in the org for the given types."
)
for change in self.return_values:
self.logger.info("{MemberType}: {MemberName}".format(**change))
self.return_values = filtered
return self.return_values


Expand All @@ -184,6 +174,15 @@ def _run_task(self):
"description": "The path to write the retrieved metadata",
"required": False,
}
retrieve_components_task_options["include"] = {
"description": "Components will be included if one of these names"
"is part of either the metadata type or name. "
"Example: ``-o include CustomField,Admin`` matches both "
"``CustomField: Favorite_Color__c`` and ``Profile: Admin``"
}
retrieve_components_task_options["exclude"] = {
"description": "Exclude components matching this name."
}
retrieve_components_task_options[
"namespace_tokenize"
] = BaseRetrieveMetadata.task_options["namespace_tokenize"]
Expand All @@ -194,6 +193,11 @@ class RetrieveComponents(ListComponents, BaseSalesforceApiTask):

def _init_options(self, kwargs):
super(RetrieveComponents, self)._init_options(kwargs)
self.options["include"] = process_list_arg(self.options.get("include", []))
self.options["exclude"] = process_list_arg(self.options.get("exclude", []))
self._include = self.options["include"]
self._exclude = self.options["exclude"]
self._exclude.extend(self.project_config.project__source__ignore or [])

package_directories = []
default_package_directory = None
Expand Down Expand Up @@ -224,13 +228,13 @@ def _init_options(self, kwargs):
self.options["path"] = path

def _run_task(self):
changes = self._get_components()
filtered, ignored = ListChanges._filter_changes(self, changes)
components = self._get_components()
filtered, ignored = ListChanges._filter_changes(self, components)
if not filtered:
self.logger.info("No changes to retrieve")
self.logger.info("No components to retrieve")
return
for change in filtered:
self.logger.info("{MemberType}: {MemberName}".format(**change))
for cmp in filtered:
self.logger.info("{MemberType}: {MemberName}".format(**cmp))

target = os.path.realpath(self.options["path"])
package_xml_opts = {}
Expand All @@ -242,7 +246,6 @@ def _run_task(self):
"uninstall_class": self.project_config.project__package__uninstall_class,
}
)

retrieve_components(
filtered,
self.org_config,
Expand Down
75 changes: 60 additions & 15 deletions cumulusci/tasks/salesforce/tests/test_nonsourcetracking.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@
import pytest
import responses

from cumulusci.core.exceptions import CumulusCIException, SfdxOrgException
from cumulusci.core.exceptions import (
CumulusCIException,
SfdxOrgException,
TaskOptionsError,
)
from cumulusci.tasks.salesforce import DescribeMetadataTypes
from cumulusci.tasks.salesforce.nonsourcetracking import (
ListComponents,
Expand Down Expand Up @@ -104,7 +108,7 @@ class TestListComponents:
],
)
def test_check_sfdx_output(self, cmd, create_task_fixture, return_code, result):
options = {"api_version": 44.0, "exclude": "Ignore"}
options = {"api_version": 44.0}
task = create_task_fixture(ListComponents, options)
cmd.return_value = mock.Mock(
stderr=io.BytesIO(b""), stdout=io.BytesIO(result), returncode=return_code
Expand All @@ -119,7 +123,13 @@ def test_check_sfdx_output(self, cmd, create_task_fixture, return_code, result):
else:
assert task._run_task() == []

@pytest.mark.parametrize("options", [{"include": "alpha"}, {"exclude": "beta"}])
@pytest.mark.parametrize(
"options",
[
{"api_version": 44.0, "metadata_types": "FlowDefinition"},
{"api_version": 44.0, "metadata_types": "Index"},
],
)
def test_check_sfdx_result(self, cmd, create_task_fixture, options):
task = create_task_fixture(ListComponents, options)
result = b"""{
Expand Down Expand Up @@ -161,16 +171,41 @@ def test_check_sfdx_result(self, cmd, create_task_fixture, options):
messages = []
task._init_task()
with mock.patch.object(
ListNonSourceTrackable, "_run_task", return_value=["FlowDefinition"]
ListNonSourceTrackable,
"_run_task",
return_value=["FlowDefinition", "SharingRules"],
):
task.logger = mock.Mock()
task.logger.info = messages.append
components = task._run_task()
assert components == [
{"MemberType": "FlowDefinition", "MemberName": "alpha"}
]
assert "Found 2 non source trackable components in the org." in messages
assert "1 remaining components after filtering." in messages

if task.options["metadata_types"] == ["Index"]:
with pytest.raises(TaskOptionsError):
task._run_task()
else:
task.logger = mock.Mock()
task.logger.info = messages.append
components = task._run_task()
assert cmd.call_count == 1
assert (
"sfdx force:mdapi:listmetadata -a 44.0 -m FlowDefinition --json"
in cmd.call_args[0][0]
)
assert components == [
{
"MemberType": "FlowDefinition",
"MemberName": "alpha",
"lastModifiedByName": "User User",
"lastModifiedDate": "2024-01-02T06:50:07.000Z",
},
{
"MemberType": "FlowDefinition",
"MemberName": "beta",
"lastModifiedByName": "User User",
"lastModifiedDate": "2024-01-02T06:50:07.000Z",
},
]
assert (
"Found 2 non source trackable components in the org for the given types."
in messages
)


@mock.patch("cumulusci.tasks.salesforce.sourcetracking.sfdx")
Expand Down Expand Up @@ -200,8 +235,18 @@ def test_run_task(self, sfdx, create_task_fixture):
ListComponents,
"_get_components",
return_value=[
{"MemberType": "FlowDefinition", "MemberName": "alpha"},
{"MemberType": "FlowDefinition", "MemberName": "beta"},
{
"MemberType": "FlowDefinition",
"MemberName": "alpha",
"lastModifiedByName": "User User",
"lastModifiedDate": "2024-01-02T06:50:07.000Z",
},
{
"MemberType": "FlowDefinition",
"MemberName": "beta",
"lastModifiedByName": "User User",
"lastModifiedDate": "2024-01-02T06:50:07.000Z",
},
],
):
task._run_task()
Expand All @@ -222,4 +267,4 @@ def test_run_task__no_changes(self, sfdx, create_task_fixture):
task.logger = mock.Mock()
task.logger.info = messages.append
task._run_task()
assert "No changes to retrieve" in messages
assert "No components to retrieve" in messages

0 comments on commit 78ab6ab

Please sign in to comment.