Skip to content

Commit ae819fe

Browse files
committed
An output-dir flag option as a parameter for user to define the retrieve changes path apart from force-app folder.something very similar to sfcli
1 parent 950f27a commit ae819fe

2 files changed

Lines changed: 68 additions & 14 deletions

File tree

cumulusci/tasks/salesforce/sourcetracking.py

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import re
66
import time
77
from collections import defaultdict
8+
from typing import Optional
89

910
from cumulusci.core.config import BaseProjectConfig, ScratchOrgConfig, TaskConfig
1011
from cumulusci.core.exceptions import ProjectConfigNotFound
@@ -223,9 +224,10 @@ def retrieve_components(
223224
extra_package_xml_opts: dict,
224225
namespace_tokenize: str,
225226
api_version: str,
226-
project_config: BaseProjectConfig = None,
227+
project_config: Optional[BaseProjectConfig] = None,
227228
retrieve_complete_profile: bool = False,
228229
capture_output: bool = False,
230+
output_dir: Optional[str] = None,
229231
):
230232
"""Retrieve specified components from an org into a target folder.
231233
@@ -272,12 +274,20 @@ def retrieve_components(
272274
json.dump(
273275
{"packageDirectories": [{"path": "force-app", "default": True}]}, f
274276
)
275-
sfdx(
276-
"project convert mdapi",
277-
log_note="Converting to DX format",
278-
args=["-r", target, "-d", "force-app"],
279-
check_return=True,
280-
)
277+
convert_output_dir = output_dir if output_dir else "force-app"
278+
try:
279+
sfdx(
280+
"project convert mdapi",
281+
log_note="Converting to DX format",
282+
args=["-r", target, "-d", convert_output_dir],
283+
check_return=True,
284+
)
285+
except Exception as e:
286+
if "No results to format" in str(e):
287+
raise Exception(
288+
f"No metadata found to convert in '{target}'. Please check the folder path or specify a different output directory using the output_dir option."
289+
)
290+
raise
281291

282292
# If retrieve_complete_profile is True, separate the profiles from
283293
# components to retrieve complete profile
@@ -323,13 +333,21 @@ def retrieve_components(
323333
cls_retrieve_profile()
324334
if md_format:
325335
# Convert back to metadata format
326-
sfdx(
327-
"project convert source",
328-
log_note="Converting back to metadata format",
329-
args=["-r", "force-app", "-d", target],
330-
capture_output=capture_output,
331-
check_return=True,
332-
)
336+
convert_output_dir = output_dir if output_dir else target
337+
try:
338+
sfdx(
339+
"project convert source",
340+
log_note="Converting back to metadata format",
341+
args=["-r", "force-app", "-d", convert_output_dir],
342+
capture_output=capture_output,
343+
check_return=True,
344+
)
345+
except Exception as e:
346+
if "No results to format" in str(e):
347+
raise Exception(
348+
f"No DX source found to convert in 'force-app'. Please check the output directory or folder path."
349+
)
350+
raise
333351

334352
# Reinject namespace tokens
335353
if namespace_tokenize:
@@ -410,6 +428,7 @@ def _run_task(self):
410428
self.logger.info("{MemberType}: {MemberName}".format(**change))
411429

412430
target = os.path.realpath(self.options["path"])
431+
output_dir = self.options.get("output_dir")
413432
package_xml_opts = {}
414433
if self.options["path"] == "src":
415434
package_xml_opts.update(
@@ -430,6 +449,7 @@ def _run_task(self):
430449
extra_package_xml_opts=package_xml_opts,
431450
project_config=self.project_config,
432451
retrieve_complete_profile=self.options["retrieve_complete_profile"],
452+
output_dir=output_dir,
433453
)
434454

435455
if self.options["snapshot"]:

cumulusci/tasks/salesforce/tests/test_sourcetracking.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,40 @@ def test_run_task__no_changes(self, sfdx, create_task_fixture):
208208
task._run_task()
209209
assert "No changes to retrieve" in messages
210210

211+
def test_run_task__output_dir(self, sfdx, create_task_fixture):
212+
sfdx_calls = []
213+
sfdx.side_effect = lambda cmd, *args, **kw: sfdx_calls.append(cmd)
214+
215+
with temporary_dir():
216+
task = create_task_fixture(
217+
RetrieveChanges, {"include": "Test", "namespace_tokenize": "ns", "output_dir": "custom_output"}
218+
)
219+
task._init_task()
220+
task.tooling = mock.Mock()
221+
task.tooling.query_all.return_value = {
222+
"totalSize": 1,
223+
"records": [
224+
{
225+
"MemberType": "CustomObject",
226+
"MemberName": "Test__c",
227+
"RevisionCounter": 1,
228+
}
229+
],
230+
}
231+
with mock.patch.object(
232+
pathlib.Path, "exists", return_value=True
233+
), mock.patch.object(
234+
pathlib.Path, "is_dir", return_value=True
235+
):
236+
task._run_task()
237+
238+
assert sfdx_calls == [
239+
"project convert mdapi",
240+
"project retrieve start",
241+
"project convert source",
242+
]
243+
assert os.path.exists(os.path.join("custom_output", "package.xml"))
244+
211245

212246
class TestSnapshotChanges:
213247
@mock.patch("cumulusci.tasks.salesforce.sourcetracking.sfdx")

0 commit comments

Comments
 (0)