cumulusci-plus 5.0.24__py3-none-any.whl → 5.0.25__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of cumulusci-plus might be problematic. Click here for more details.

@@ -0,0 +1,443 @@
1
+ """Tests for SFDmu task."""
2
+
3
+ import os
4
+ import tempfile
5
+ from unittest import mock
6
+
7
+ import pytest
8
+
9
+ from cumulusci.tasks.salesforce.tests.util import create_task
10
+ from cumulusci.tasks.sfdmu.sfdmu import SfdmuTask
11
+
12
+
13
+ class TestSfdmuTask:
14
+ """Test cases for SfdmuTask."""
15
+
16
+ def test_init_options_validates_path(self):
17
+ """Test that _init_options validates the path exists and contains export.json."""
18
+ with tempfile.TemporaryDirectory() as temp_dir:
19
+ # Create export.json file
20
+ export_json_path = os.path.join(temp_dir, "export.json")
21
+ with open(export_json_path, "w") as f:
22
+ f.write('{"test": "data"}')
23
+
24
+ # Test valid path using create_task helper
25
+ task = create_task(
26
+ SfdmuTask, {"source": "dev", "target": "qa", "path": temp_dir}
27
+ )
28
+ assert task.options["path"] == os.path.abspath(temp_dir)
29
+
30
+ def test_init_options_raises_error_for_missing_path(self):
31
+ """Test that _init_options raises error for missing path."""
32
+ with pytest.raises(Exception): # TaskOptionsError
33
+ create_task(
34
+ SfdmuTask,
35
+ {"source": "dev", "target": "qa", "path": "/nonexistent/path"},
36
+ )
37
+
38
+ def test_init_options_raises_error_for_missing_export_json(self):
39
+ """Test that _init_options raises error for missing export.json."""
40
+ with tempfile.TemporaryDirectory() as temp_dir:
41
+ with pytest.raises(Exception): # TaskOptionsError
42
+ create_task(
43
+ SfdmuTask, {"source": "dev", "target": "qa", "path": temp_dir}
44
+ )
45
+
46
+ def test_validate_org_csvfile(self):
47
+ """Test that _validate_org returns None for csvfile."""
48
+ with tempfile.TemporaryDirectory() as temp_dir:
49
+ # Create export.json file
50
+ export_json_path = os.path.join(temp_dir, "export.json")
51
+ with open(export_json_path, "w") as f:
52
+ f.write('{"test": "data"}')
53
+
54
+ task = create_task(
55
+ SfdmuTask, {"source": "csvfile", "target": "csvfile", "path": temp_dir}
56
+ )
57
+
58
+ result = task._validate_org("csvfile")
59
+ assert result is None
60
+
61
+ def test_validate_org_missing_keychain(self):
62
+ """Test that _validate_org raises error when keychain is None."""
63
+ with tempfile.TemporaryDirectory() as temp_dir:
64
+ # Create export.json file
65
+ export_json_path = os.path.join(temp_dir, "export.json")
66
+ with open(export_json_path, "w") as f:
67
+ f.write('{"test": "data"}')
68
+
69
+ task = create_task(
70
+ SfdmuTask, {"source": "dev", "target": "qa", "path": temp_dir}
71
+ )
72
+
73
+ # Mock the keychain to be None
74
+ task.project_config.keychain = None
75
+
76
+ with pytest.raises(Exception): # TaskOptionsError
77
+ task._validate_org("dev")
78
+
79
+ def test_get_sf_org_name_sfdx_alias(self):
80
+ """Test _get_sf_org_name with sfdx_alias."""
81
+ with tempfile.TemporaryDirectory() as temp_dir:
82
+ # Create export.json file
83
+ export_json_path = os.path.join(temp_dir, "export.json")
84
+ with open(export_json_path, "w") as f:
85
+ f.write('{"test": "data"}')
86
+
87
+ task = create_task(
88
+ SfdmuTask, {"source": "dev", "target": "qa", "path": temp_dir}
89
+ )
90
+
91
+ mock_org_config = mock.Mock()
92
+ mock_org_config.sfdx_alias = "test_alias"
93
+ mock_org_config.username = "test@example.com"
94
+
95
+ result = task._get_sf_org_name(mock_org_config)
96
+ assert result == "test_alias"
97
+
98
+ def test_get_sf_org_name_username(self):
99
+ """Test _get_sf_org_name with username fallback."""
100
+ with tempfile.TemporaryDirectory() as temp_dir:
101
+ # Create export.json file
102
+ export_json_path = os.path.join(temp_dir, "export.json")
103
+ with open(export_json_path, "w") as f:
104
+ f.write('{"test": "data"}')
105
+
106
+ task = create_task(
107
+ SfdmuTask, {"source": "dev", "target": "qa", "path": temp_dir}
108
+ )
109
+
110
+ mock_org_config = mock.Mock()
111
+ mock_org_config.sfdx_alias = None
112
+ mock_org_config.username = "test@example.com"
113
+
114
+ result = task._get_sf_org_name(mock_org_config)
115
+ assert result == "test@example.com"
116
+
117
+ def test_create_execute_directory(self):
118
+ """Test _create_execute_directory creates directory and copies files."""
119
+ with tempfile.TemporaryDirectory() as base_dir:
120
+ # Create test files
121
+ export_json = os.path.join(base_dir, "export.json")
122
+ test_csv = os.path.join(base_dir, "test.csv")
123
+ test_txt = os.path.join(base_dir, "test.txt") # Should not be copied
124
+
125
+ with open(export_json, "w") as f:
126
+ f.write('{"test": "data"}')
127
+ with open(test_csv, "w") as f:
128
+ f.write("col1,col2\nval1,val2")
129
+ with open(test_txt, "w") as f:
130
+ f.write("text file")
131
+
132
+ # Create subdirectory (should not be copied)
133
+ subdir = os.path.join(base_dir, "subdir")
134
+ os.makedirs(subdir)
135
+ with open(os.path.join(subdir, "file.txt"), "w") as f:
136
+ f.write("subdir file")
137
+
138
+ task = create_task(
139
+ SfdmuTask, {"source": "dev", "target": "qa", "path": base_dir}
140
+ )
141
+
142
+ execute_path = task._create_execute_directory(base_dir)
143
+
144
+ # Check that execute directory was created
145
+ assert os.path.exists(execute_path)
146
+ assert execute_path == os.path.join(base_dir, "execute")
147
+
148
+ # Check that files were copied
149
+ assert os.path.exists(os.path.join(execute_path, "export.json"))
150
+ assert os.path.exists(os.path.join(execute_path, "test.csv"))
151
+ assert not os.path.exists(
152
+ os.path.join(execute_path, "test.txt")
153
+ ) # Not a valid file type
154
+ assert not os.path.exists(
155
+ os.path.join(execute_path, "subdir")
156
+ ) # Not a file
157
+
158
+ # Check file contents
159
+ with open(os.path.join(execute_path, "export.json"), "r") as f:
160
+ assert f.read() == '{"test": "data"}'
161
+ with open(os.path.join(execute_path, "test.csv"), "r") as f:
162
+ assert f.read() == "col1,col2\nval1,val2"
163
+
164
+ def test_create_execute_directory_removes_existing(self):
165
+ """Test that _create_execute_directory removes existing execute directory."""
166
+ with tempfile.TemporaryDirectory() as base_dir:
167
+ # Create existing execute directory with files
168
+ execute_dir = os.path.join(base_dir, "execute")
169
+ os.makedirs(execute_dir)
170
+ with open(os.path.join(execute_dir, "old_file.json"), "w") as f:
171
+ f.write('{"old": "data"}')
172
+
173
+ # Create export.json in base directory
174
+ export_json = os.path.join(base_dir, "export.json")
175
+ with open(export_json, "w") as f:
176
+ f.write('{"test": "data"}')
177
+
178
+ task = create_task(
179
+ SfdmuTask, {"source": "dev", "target": "qa", "path": base_dir}
180
+ )
181
+
182
+ execute_path = task._create_execute_directory(base_dir)
183
+
184
+ # Check that old file was removed
185
+ assert not os.path.exists(os.path.join(execute_path, "old_file.json"))
186
+ # Check that new file was copied
187
+ assert os.path.exists(os.path.join(execute_path, "export.json"))
188
+
189
+ def test_inject_namespace_tokens_csvfile_target(self):
190
+ """Test that namespace injection is skipped when target is csvfile."""
191
+ with tempfile.TemporaryDirectory() as execute_dir:
192
+ # Create test files
193
+ test_json = os.path.join(execute_dir, "test.json")
194
+ with open(test_json, "w") as f:
195
+ f.write('{"field": "%%%NAMESPACE%%%Test"}')
196
+
197
+ # Create export.json file
198
+ export_json_path = os.path.join(execute_dir, "export.json")
199
+ with open(export_json_path, "w") as f:
200
+ f.write('{"test": "data"}')
201
+
202
+ task = create_task(
203
+ SfdmuTask, {"source": "dev", "target": "csvfile", "path": execute_dir}
204
+ )
205
+
206
+ # Should not raise any errors and files should remain unchanged
207
+ task._inject_namespace_tokens(execute_dir, None)
208
+
209
+ # Check that file content was not changed
210
+ with open(test_json, "r") as f:
211
+ assert f.read() == '{"field": "%%%NAMESPACE%%%Test"}'
212
+
213
+ @mock.patch("cumulusci.tasks.sfdmu.sfdmu.determine_managed_mode")
214
+ def test_inject_namespace_tokens_managed_mode(self, mock_determine_managed):
215
+ """Test namespace injection in managed mode."""
216
+ mock_determine_managed.return_value = True
217
+
218
+ with tempfile.TemporaryDirectory() as execute_dir:
219
+ # Create test files with namespace tokens
220
+ test_json = os.path.join(execute_dir, "test.json")
221
+ test_csv = os.path.join(execute_dir, "test.csv")
222
+
223
+ with open(test_json, "w") as f:
224
+ f.write(
225
+ '{"field": "%%%NAMESPACE%%%Test", "org": "%%%NAMESPACED_ORG%%%Value"}'
226
+ )
227
+ with open(test_csv, "w") as f:
228
+ f.write("Name,%%%NAMESPACE%%%Field\nTest,Value")
229
+
230
+ # Create filename with namespace token
231
+ filename_with_token = os.path.join(execute_dir, "___NAMESPACE___test.json")
232
+ with open(filename_with_token, "w") as f:
233
+ f.write('{"test": "data"}')
234
+
235
+ # Create export.json file
236
+ export_json_path = os.path.join(execute_dir, "export.json")
237
+ with open(export_json_path, "w") as f:
238
+ f.write('{"test": "data"}')
239
+
240
+ task = create_task(
241
+ SfdmuTask, {"source": "dev", "target": "qa", "path": execute_dir}
242
+ )
243
+
244
+ # Mock the project config namespace
245
+ task.project_config.project__package__namespace = "testns"
246
+
247
+ mock_org_config = mock.Mock()
248
+ mock_org_config.namespace = "testns"
249
+
250
+ task._inject_namespace_tokens(execute_dir, mock_org_config)
251
+
252
+ # Check that namespace tokens were replaced in content
253
+ with open(test_json, "r") as f:
254
+ content = f.read()
255
+ assert "testns__Test" in content
256
+ assert "testns__Value" in content
257
+
258
+ with open(test_csv, "r") as f:
259
+ content = f.read()
260
+ assert "testns__Field" in content
261
+
262
+ # Check that filename token was replaced
263
+ expected_filename = os.path.join(execute_dir, "testns__test.json")
264
+ assert os.path.exists(expected_filename)
265
+ assert not os.path.exists(filename_with_token)
266
+
267
+ @mock.patch("cumulusci.tasks.sfdmu.sfdmu.determine_managed_mode")
268
+ def test_inject_namespace_tokens_unmanaged_mode(self, mock_determine_managed):
269
+ """Test namespace injection in unmanaged mode."""
270
+ mock_determine_managed.return_value = False
271
+
272
+ with tempfile.TemporaryDirectory() as execute_dir:
273
+ # Create test files with namespace tokens
274
+ test_json = os.path.join(execute_dir, "test.json")
275
+ with open(test_json, "w") as f:
276
+ f.write(
277
+ '{"field": "%%%NAMESPACE%%%Test", "org": "%%%NAMESPACED_ORG%%%Value"}'
278
+ )
279
+
280
+ # Create export.json file
281
+ export_json_path = os.path.join(execute_dir, "export.json")
282
+ with open(export_json_path, "w") as f:
283
+ f.write('{"test": "data"}')
284
+
285
+ task = create_task(
286
+ SfdmuTask, {"source": "dev", "target": "qa", "path": execute_dir}
287
+ )
288
+
289
+ # Mock the project config namespace
290
+ task.project_config.project__package__namespace = "testns"
291
+
292
+ mock_org_config = mock.Mock()
293
+ mock_org_config.namespace = "testns"
294
+
295
+ task._inject_namespace_tokens(execute_dir, mock_org_config)
296
+
297
+ # Check that namespace tokens were replaced with empty strings
298
+ with open(test_json, "r") as f:
299
+ content = f.read()
300
+ assert "Test" in content # %%NAMESPACE%% removed
301
+ assert "Value" in content # %%NAMESPACED_ORG%% removed
302
+ assert "%%%NAMESPACE%%%" not in content
303
+ assert "%%%NAMESPACED_ORG%%%" not in content
304
+
305
+ @mock.patch("cumulusci.tasks.sfdmu.sfdmu.determine_managed_mode")
306
+ def test_inject_namespace_tokens_namespaced_org(self, mock_determine_managed):
307
+ """Test namespace injection with namespaced org."""
308
+ mock_determine_managed.return_value = True
309
+
310
+ with tempfile.TemporaryDirectory() as execute_dir:
311
+ # Create test file with namespaced org token
312
+ test_json = os.path.join(execute_dir, "test.json")
313
+ with open(test_json, "w") as f:
314
+ f.write('{"field": "%%%NAMESPACED_ORG%%%Test"}')
315
+
316
+ # Create export.json file
317
+ export_json_path = os.path.join(execute_dir, "export.json")
318
+ with open(export_json_path, "w") as f:
319
+ f.write('{"test": "data"}')
320
+
321
+ task = create_task(
322
+ SfdmuTask, {"source": "dev", "target": "qa", "path": execute_dir}
323
+ )
324
+
325
+ # Mock the project config namespace
326
+ task.project_config.project__package__namespace = "testns"
327
+
328
+ mock_org_config = mock.Mock()
329
+ mock_org_config.namespace = (
330
+ "testns" # Same as project namespace = namespaced org
331
+ )
332
+
333
+ task._inject_namespace_tokens(execute_dir, mock_org_config)
334
+
335
+ # Check that namespaced org token was replaced
336
+ with open(test_json, "r") as f:
337
+ content = f.read()
338
+ assert "testns__Test" in content
339
+ assert "%%%NAMESPACED_ORG%%%" not in content
340
+
341
+ @mock.patch("cumulusci.tasks.sfdmu.sfdmu.determine_managed_mode")
342
+ def test_inject_namespace_tokens_non_namespaced_org(self, mock_determine_managed):
343
+ """Test namespace injection with non-namespaced org."""
344
+ mock_determine_managed.return_value = True
345
+
346
+ with tempfile.TemporaryDirectory() as execute_dir:
347
+ # Create test file with namespaced org token
348
+ test_json = os.path.join(execute_dir, "test.json")
349
+ with open(test_json, "w") as f:
350
+ f.write('{"field": "%%%NAMESPACED_ORG%%%Test"}')
351
+
352
+ # Create export.json file
353
+ export_json_path = os.path.join(execute_dir, "export.json")
354
+ with open(export_json_path, "w") as f:
355
+ f.write('{"test": "data"}')
356
+
357
+ task = create_task(
358
+ SfdmuTask, {"source": "dev", "target": "qa", "path": execute_dir}
359
+ )
360
+
361
+ # Mock the project config namespace
362
+ task.project_config.project__package__namespace = "testns"
363
+
364
+ mock_org_config = mock.Mock()
365
+ mock_org_config.namespace = (
366
+ "differentns" # Different from project namespace
367
+ )
368
+
369
+ task._inject_namespace_tokens(execute_dir, mock_org_config)
370
+
371
+ # Check that namespaced org token was replaced with empty string
372
+ with open(test_json, "r") as f:
373
+ content = f.read()
374
+ assert "Test" in content # %%NAMESPACED_ORG%% removed
375
+ assert "%%%NAMESPACED_ORG%%%" not in content
376
+ assert "testns__" not in content # Should not have namespace prefix
377
+
378
+ def test_inject_namespace_tokens_no_namespace(self):
379
+ """Test namespace injection when project has no namespace."""
380
+ with tempfile.TemporaryDirectory() as execute_dir:
381
+ # Create test file with namespace tokens
382
+ test_json = os.path.join(execute_dir, "test.json")
383
+ with open(test_json, "w") as f:
384
+ f.write('{"field": "%%%NAMESPACE%%%Test"}')
385
+
386
+ # Create export.json file
387
+ export_json_path = os.path.join(execute_dir, "export.json")
388
+ with open(export_json_path, "w") as f:
389
+ f.write('{"test": "data"}')
390
+
391
+ task = create_task(
392
+ SfdmuTask, {"source": "dev", "target": "qa", "path": execute_dir}
393
+ )
394
+
395
+ # Mock the project config namespace
396
+ task.project_config.project__package__namespace = None
397
+
398
+ mock_org_config = mock.Mock()
399
+ mock_org_config.namespace = None
400
+
401
+ task._inject_namespace_tokens(execute_dir, mock_org_config)
402
+
403
+ # Check that namespace tokens were not processed (due to circular import issue)
404
+ with open(test_json, "r") as f:
405
+ content = f.read()
406
+ assert (
407
+ "%%%NAMESPACE%%%Test" in content
408
+ ) # Tokens remain unchanged due to import issue
409
+
410
+ def test_additional_params_option_exists(self):
411
+ """Test that additional_params option is properly defined in task_options."""
412
+ # Check that the additional_params option is defined
413
+ assert "additional_params" in SfdmuTask.task_options
414
+ assert SfdmuTask.task_options["additional_params"]["required"] is False
415
+ assert (
416
+ "Additional parameters"
417
+ in SfdmuTask.task_options["additional_params"]["description"]
418
+ )
419
+
420
+ def test_additional_params_parsing_logic(self):
421
+ """Test that additional_params parsing logic works correctly."""
422
+ # Test the splitting logic that would be used in the task
423
+ additional_params = "-no-warnings -m -t error"
424
+ additional_args = additional_params.split()
425
+ expected_args = ["-no-warnings", "-m", "-t", "error"]
426
+ assert additional_args == expected_args
427
+
428
+ def test_additional_params_empty_string_logic(self):
429
+ """Test that empty additional_params are handled correctly."""
430
+ # Test the splitting logic with empty string
431
+ additional_params = ""
432
+ additional_args = additional_params.split()
433
+ assert additional_args == []
434
+
435
+ def test_additional_params_none_logic(self):
436
+ """Test that None additional_params are handled correctly."""
437
+ # Test the logic that would be used in the task
438
+ additional_params = None
439
+ if additional_params:
440
+ additional_args = additional_params.split()
441
+ else:
442
+ additional_args = []
443
+ assert additional_args == []
@@ -245,6 +245,10 @@ def inject_namespace(
245
245
  ):
246
246
  """Replaces %%%NAMESPACE%%% in file content and ___NAMESPACE___ in file name
247
247
  with either '' if no namespace is provided or 'namespace__' if provided.
248
+
249
+ Also handles:
250
+ - %%%MANAGED_OR_NAMESPACED_ORG%%% and ___MANAGED_OR_NAMESPACED_ORG___ tokens
251
+ which are replaced with 'namespace__' if managed=True OR namespaced_org=True
248
252
  """
249
253
 
250
254
  # Handle namespace and filename tokens
@@ -264,7 +268,7 @@ def inject_namespace(
264
268
  # Handle tokens %%%NAMESPACED_ORG%%% and ___NAMESPACED_ORG___
265
269
  namespaced_org_token = "%%%NAMESPACED_ORG%%%"
266
270
  namespaced_org_file_token = "___NAMESPACED_ORG___"
267
- namespaced_org = namespace + "__" if namespaced_org else ""
271
+ namespaced_org = (namespace + "__") if namespaced_org and namespace else ""
268
272
 
269
273
  # Handle token %%%NAMESPACE_OR_C%%% for lightning components
270
274
  namespace_or_c_token = "%%%NAMESPACE_OR_C%%%"
@@ -274,6 +278,13 @@ def inject_namespace(
274
278
  namespaced_org_or_c_token = "%%%NAMESPACED_ORG_OR_C%%%"
275
279
  namespaced_org_or_c = namespace if namespaced_org else "c"
276
280
 
281
+ # Handle new tokens %%%MANAGED_OR_NAMESPACED_ORG%%% and ___MANAGED_OR_NAMESPACED_ORG___
282
+ managed_or_namespaced_org_token = "%%%MANAGED_OR_NAMESPACED_ORG%%%"
283
+ managed_or_namespaced_org_file_token = "___MANAGED_OR_NAMESPACED_ORG___"
284
+ managed_or_namespaced_org = (
285
+ (namespace + "__") if ((managed) or (namespaced_org)) and namespace else ""
286
+ )
287
+
277
288
  orig_name = name
278
289
  prev_content = content
279
290
  content = content.replace(namespace_token, namespace_prefix)
@@ -324,9 +335,20 @@ def inject_namespace(
324
335
  f' {name}: Replaced {namespaced_org_or_c_token} with "{namespaced_org_or_c}"'
325
336
  )
326
337
 
338
+ # Replace new managed_or_namespaced_org token in content
339
+ prev_content = content
340
+ content = content.replace(
341
+ managed_or_namespaced_org_token, managed_or_namespaced_org
342
+ )
343
+ if logger and content != prev_content:
344
+ logger.info(
345
+ f' {name}: Replaced {managed_or_namespaced_org_token} with "{managed_or_namespaced_org}"'
346
+ )
347
+
327
348
  # Replace namespace token in file name
328
349
  name = name.replace(filename_token, namespace_prefix)
329
350
  name = name.replace(namespaced_org_file_token, namespaced_org)
351
+ name = name.replace(managed_or_namespaced_org_file_token, managed_or_namespaced_org)
330
352
  if logger and name != orig_name:
331
353
  logger.info(f" {orig_name}: renamed to {name}")
332
354
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cumulusci-plus
3
- Version: 5.0.24
3
+ Version: 5.0.25
4
4
  Summary: Build and release tools for Salesforce developers
5
5
  Project-URL: Homepage, https://github.com/jorgesolebur/CumulusCI
6
6
  Project-URL: Changelog, https://cumulusci.readthedocs.io/en/stable/history.html
@@ -128,7 +128,7 @@ license](https://github.com/SFDO-Tooling/CumulusCI/blob/main/LICENSE)
128
128
  and is not covered by the Salesforce Master Subscription Agreement.
129
129
 
130
130
  <!-- Changelog -->
131
- ## v5.0.24 (2025-09-29)
131
+ ## v5.0.25 (2025-10-09)
132
132
 
133
133
  <!-- Release notes generated using configuration in .github/release.yml at main -->
134
134
 
@@ -136,9 +136,9 @@ and is not covered by the Salesforce Master Subscription Agreement.
136
136
 
137
137
  ### Changes
138
138
 
139
- - Enhance when condition for flows. by [@rupeshjSFDC](https://github.com/rupeshjSFDC) in [#80](https://github.com/jorgesolebur/CumulusCI/pull/80)
140
- - Can we update the upgrade command displayed in terminal by [@jorgesolebur](https://github.com/jorgesolebur) in [#77](https://github.com/jorgesolebur/CumulusCI/pull/77)
141
- - CCI Package command support. by [@rupeshjSFDC](https://github.com/rupeshjSFDC) in [#83](https://github.com/jorgesolebur/CumulusCI/pull/83)
142
- - Simplify Version dependency ids and Update / Get Package version Id. by [@rupeshjSFDC](https://github.com/rupeshjSFDC) in [#85](https://github.com/jorgesolebur/CumulusCI/pull/85)
139
+ - PM-2198 Add NAMESPACE injection in assign_permission_sets by [@jorgesolebur](https://github.com/jorgesolebur) in [#87](https://github.com/jorgesolebur/CumulusCI/pull/87)
140
+ - Add update named credential and external credential tasks by [@rupeshjSFDC](https://github.com/rupeshjSFDC) in [#89](https://github.com/jorgesolebur/CumulusCI/pull/89)
141
+ - Fix external credential POST or PUT format. by [@rupeshjSFDC](https://github.com/rupeshjSFDC) in [#92](https://github.com/jorgesolebur/CumulusCI/pull/92)
142
+ - PM-2203 Create a CCI task for CCI to wrap SFDMU and apply namespace token replacement before executing sf sfdmu run command by [@jorgesolebur](https://github.com/jorgesolebur) in [#88](https://github.com/jorgesolebur/CumulusCI/pull/88)
143
143
 
144
- **Full Changelog**: https://github.com/jorgesolebur/CumulusCI/compare/v5.0.23...v5.0.24
144
+ **Full Changelog**: https://github.com/jorgesolebur/CumulusCI/compare/v5.0.24...v5.0.25
@@ -1,8 +1,8 @@
1
- cumulusci/__about__.py,sha256=6TaCsfGav1m2nmlsTzscaT8f4Zvmz_dnfox29XwpCYY,23
1
+ cumulusci/__about__.py,sha256=PQnP57RP4O20oRC3LPTUDrGtol6aiAfs6ybzWQMwca4,23
2
2
  cumulusci/__init__.py,sha256=jdanFQ_i8vbdO7Eltsf4pOfvV4mwa_Osyc4gxWKJ8ng,764
3
3
  cumulusci/__main__.py,sha256=kgRH-n5AJrH_daCK_EJwH7azAUxdXEmpi-r-dPGMR6Y,43
4
4
  cumulusci/conftest.py,sha256=AIL98BDwNAQtdo8YFmLKwav0tmrQ5dpbw1cX2FyGouQ,5108
5
- cumulusci/cumulusci.yml,sha256=E7iKo4NjDIf4Xuxx_di9KLbivNTmpYJ21ldhI3uyRLI,74238
5
+ cumulusci/cumulusci.yml,sha256=5JDmQN332wDcCRoFQamUCl7XhGEdhdmpEDMKOFhOSKM,74871
6
6
  cumulusci/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
7
  cumulusci/cli/cci.py,sha256=yAq8jFoGde6g_1TeAAjzZYsk77itiONCQGBFe3g3nOs,11836
8
8
  cumulusci/cli/error.py,sha256=znj0YN8D2Grozm1u7mZAsJlmmdGebbuy0c1ofQluL4Q,4410
@@ -14,7 +14,7 @@ cumulusci/cli/project.py,sha256=GKFTNgvB_xj5yIk2Wwj3gwAN3-eXCZTk6PhwLYOH6cI,1331
14
14
  cumulusci/cli/robot.py,sha256=hGfa3UQkwxAyuY0MlV6KzUqhwwJCvm-BPo742cTOKIQ,3847
15
15
  cumulusci/cli/runtime.py,sha256=PFBy-idQy6WsUijiU61hd4-jL12UH_PRGHATJxsNacU,6991
16
16
  cumulusci/cli/service.py,sha256=Pv2wnCFUHBhNeXY3-m_ct8KGul21UyFt3bScxWUofME,19803
17
- cumulusci/cli/task.py,sha256=xm8lo0_LMMpcsUDv1Gj_HpW1phllyEW9IRm2lQSh5wg,10077
17
+ cumulusci/cli/task.py,sha256=7sRrbK0lkrWvnCjH4CwEpK8pzJm1lhchC5CRXmMVSRc,10688
18
18
  cumulusci/cli/ui.py,sha256=Ld-2S6Kr204SBput-1pNAVlYglzcvbV5nVA_rGXlAo8,7346
19
19
  cumulusci/cli/utils.py,sha256=Bl-l8eOXxzi6E_DsWGGGeefwZxrVg7Zo52BIwoNhKH8,5522
20
20
  cumulusci/cli/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -28,7 +28,7 @@ cumulusci/cli/tests/test_project.py,sha256=VMwsmyf2Cww9B6zuxh41kiXpyvozEdvfUAOdE
28
28
  cumulusci/cli/tests/test_robot.py,sha256=v2CCYYOg9ocEN-xvO5MXY_XsIbwu5_Z3mwLYZjisn74,6523
29
29
  cumulusci/cli/tests/test_runtime.py,sha256=omkRBqLfdmjooV0HvMjyYx-fiYlOa2__YJBVw1wD8os,6910
30
30
  cumulusci/cli/tests/test_service.py,sha256=fywZatIsURM2hOF1Ugl-FmkjlZUuPrJviaj1GCpOfJo,26644
31
- cumulusci/cli/tests/test_task.py,sha256=_9MrzJchShsnLqPwS2raLgDh9ukaV3MryQvV9OeuOWo,8453
31
+ cumulusci/cli/tests/test_task.py,sha256=5V7awi7hSnKfxywdYFiAO8-shGiT3KLXYg5WVj7vh5Y,11639
32
32
  cumulusci/cli/tests/test_ui.py,sha256=mxvVF_kCVuTceA_J25LUH07NIS8hmMCvuFRa3fZ2NFQ,9480
33
33
  cumulusci/cli/tests/test_utils.py,sha256=nkvUfN7m811_QPBeY2bR49KZRffAxBjxiy3bNrXCLvA,3537
34
34
  cumulusci/cli/tests/utils.py,sha256=ktmP8OXNdHOoRffTJYsujRbwCna5urhqhcRYEvikz9Y,1466
@@ -548,6 +548,8 @@ cumulusci/tasks/salesforce/sourcetracking.py,sha256=-JaZt1NNlA_dEzYsIHvFKZ9va-MM
548
548
  cumulusci/tasks/salesforce/trigger_handlers.py,sha256=cs6pDHhvi_eu0Vr8sLtfH2nrhlsF8TPrkKezjciy79o,4932
549
549
  cumulusci/tasks/salesforce/uninstall_packaged_incremental.py,sha256=9-_3S0PaVm-K6t44McBHSfRTB7KVzkHUMii4-p5PkS0,5673
550
550
  cumulusci/tasks/salesforce/update_dependencies.py,sha256=84N_hUam6wNxrnseaGMJSSDtz02cV78MKWVQzwjVecY,12225
551
+ cumulusci/tasks/salesforce/update_external_credential.py,sha256=PapMqfBWvzExGA8bFRra2SHwge_0Wt3TAT-7p1Q0iqU,21449
552
+ cumulusci/tasks/salesforce/update_named_credential.py,sha256=YDBkGW7Y7OHagk-oZRWF9wJhe0j-77Xczk-8JQZm47g,16482
551
553
  cumulusci/tasks/salesforce/update_profile.py,sha256=P8TQeWEjzXFI4hN5cUk9zMCweBerqNP08seIuYEo-RI,15163
552
554
  cumulusci/tasks/salesforce/tests/__init__.py,sha256=zEUlLU8eRXUU1HAcYdHtdAgHbdlAPPj39rcWRPEu2H4,57
553
555
  cumulusci/tasks/salesforce/tests/test_CreateCommunity.py,sha256=aepyVVrM6zfmT2UJ_pKKdgwv7DsU66F_eiwmE4EfVUo,8720
@@ -593,16 +595,23 @@ cumulusci/tasks/salesforce/tests/test_salesforce_files.py,sha256=eBeyanF7ygldukf
593
595
  cumulusci/tasks/salesforce/tests/test_sourcetracking.py,sha256=n9dyJ21OZs8P574Ds3uzVESCVl6fK0_RYv2bKI1dm3E,12540
594
596
  cumulusci/tasks/salesforce/tests/test_trigger_handlers.py,sha256=IpqnCKgGVWU0XUP4LDB10HG1LLj5VvsSfxMBa26EScs,10567
595
597
  cumulusci/tasks/salesforce/tests/test_update_dependencies.py,sha256=C7Zu115-Bi585Fu7tWy3TF9ZKDcKiu1zXzqJiOhA0L0,14679
598
+ cumulusci/tasks/salesforce/tests/test_update_external_credential.py,sha256=JcjrhMqPkMWnf0j8LIH_MjSShST8EzG2IysFQbA0w6o,33819
599
+ cumulusci/tasks/salesforce/tests/test_update_named_credential.py,sha256=ryyW7b1TGXw4-k5E3-LXzT2iQhBhnpAgTJcEQMlSdOw,37829
596
600
  cumulusci/tasks/salesforce/tests/util.py,sha256=YbeHOKyKNhKNYtd1g467a4sQ07W3SvyMAuT0E3bL6Js,2543
597
- cumulusci/tasks/salesforce/users/permsets.py,sha256=EMFX7QhSbVd1LM0ognYlaXUhYcpSY-0CbWOARRVORM0,9326
601
+ cumulusci/tasks/salesforce/users/permsets.py,sha256=93PimJELAnGu9dDf6cH9IaZAbnWLLf_ennttVOxCYp0,12415
598
602
  cumulusci/tasks/salesforce/users/photos.py,sha256=67-fQk0m9w4bf1N2WSWfsn-kwtmIuLtSpyJCqa8Cr1w,5745
599
603
  cumulusci/tasks/salesforce/users/tests/photo.mock.txt,sha256=5TgNf9xBvoNm4glnpQKXz2RJP3bkA0FkSB5BIuy7DPw,15
600
- cumulusci/tasks/salesforce/users/tests/test_permsets.py,sha256=T0j4z2iHp34il_pGq-1JZA8gw4W2PgBcL4eyOjznhJQ,36316
604
+ cumulusci/tasks/salesforce/users/tests/test_permsets.py,sha256=lF4v4tMujNW4FPYWdFnBbDCKaWRBwx6qWpy4feh5jv8,43424
601
605
  cumulusci/tasks/salesforce/users/tests/test_photos.py,sha256=PaFjz_2FKCopqM_E9Rq15Mo8xzcadQLuroruDz9Hwg0,14258
602
606
  cumulusci/tasks/sample_data/capture_sample_data.py,sha256=JQJUejFrhP6ddj1Tc_NOidM__e5BMTPUIiAdx_V1zjw,3034
603
607
  cumulusci/tasks/sample_data/load_sample_data.py,sha256=x_m8OvqoZuPUzblhhFpiQXqHHEO8Q0mL6Tr3-nOWRv0,3235
604
608
  cumulusci/tasks/sample_data/test_capture_sample_data.py,sha256=irPGIQYwqmuTXMIDeN6pz-EpjDY7T4F32mhhLvtM_ho,3999
605
609
  cumulusci/tasks/sample_data/test_load_sample_data.py,sha256=iSLRTrx2iwOanSMyKPFSn-j1YKOy1ZGFt1niV24LFH8,4168
610
+ cumulusci/tasks/sfdmu/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
611
+ cumulusci/tasks/sfdmu/sfdmu.py,sha256=W8qxTCvNqCd292JlAOpEQDaeg0KuUqUhISSYkE4RTYc,9894
612
+ cumulusci/tasks/sfdmu/tests/__init__.py,sha256=Vx3BD82OfmecnZN_5DtdAjiDqpRxgAsi9QUjFuoij2w,29
613
+ cumulusci/tasks/sfdmu/tests/test_runner.py,sha256=kWVRYspJ8nZKpP7rmV8mHIHI2WvzyM6uREbTbyrXTF4,7697
614
+ cumulusci/tasks/sfdmu/tests/test_sfdmu.py,sha256=hFf08GHvCcuO5wl2BIOjJfPOxZlN7yN1N3eC1TYX5QY,18594
606
615
  cumulusci/tasks/tests/__init__.py,sha256=iwhKnzeBJLKxpRVjvzwiRE63_zNpIBfaKLITauVph-0,24
607
616
  cumulusci/tasks/tests/conftest.py,sha256=UwLh1djIuJqz49ke1kbJtL0VoBPzll3h925QkEwlTY8,667
608
617
  cumulusci/tasks/tests/test_command.py,sha256=N-QZVJn_O-Z0_VTzO9sbfIsqadiXFSqbbJe6kzho4h8,4686
@@ -671,7 +680,7 @@ cumulusci/tests/shared_cassettes/vcr_string_templates/batchInfoList_xml.tpl,sha2
671
680
  cumulusci/tests/shared_cassettes/vcr_string_templates/batchInfo_xml.tpl,sha256=QVliMmBsCaTLx6ichcTSJEk58ejkNmKQfYchr8a62kE,553
672
681
  cumulusci/tests/shared_cassettes/vcr_string_templates/jobInfo_insert_xml.tpl,sha256=MELjgmEaKPEVMcZNO3s8fn5QjvN5qU7F1svg8tc5yoA,1113
673
682
  cumulusci/tests/shared_cassettes/vcr_string_templates/jobInfo_upsert_xml.tpl,sha256=Pk2twM954A_jndsGJXLhe1S00Sd64O6a2QNlnfj83Dw,1152
674
- cumulusci/utils/__init__.py,sha256=dJHtpKTHbXROzIljpJ_h8uG9YzvXgRqvZlPGkjYP12M,25675
683
+ cumulusci/utils/__init__.py,sha256=wLObYg1NJDZVFa_gYJ0cruDi-0sQx1PX93IheXOvzd0,26699
675
684
  cumulusci/utils/classutils.py,sha256=paXwI8ZkwLr0Wv2fhs99GXh4Jhoinye6m1UJPPrtJFM,322
676
685
  cumulusci/utils/collections.py,sha256=4XcsBCyDhNcxSL589Y6gjNONKeB7YLqQ-nlWmiZjIlo,691
677
686
  cumulusci/utils/deprecation.py,sha256=MDQ4kbAS3RhpVAA_WVCXRMDDEjJj3pq9eeBDyPNcEoc,216
@@ -744,9 +753,9 @@ cumulusci/vcs/tests/dummy_service.py,sha256=RltOUpMIhSDNrfxk0LhLqlH4ppC0sK6NC2cO
744
753
  cumulusci/vcs/tests/test_vcs_base.py,sha256=9mp6uZ3lTxY4onjUNCucp9N9aB3UylKS7_2Zu_hdAZw,24331
745
754
  cumulusci/vcs/tests/test_vcs_bootstrap.py,sha256=N0NA48-rGNIIjY3Z7PtVnNwHObSlEGDk2K55TQGI8g4,27954
746
755
  cumulusci/vcs/utils/__init__.py,sha256=py4fEcHM7Vd0M0XWznOlywxaeCtG3nEVGmELmEKVGU8,869
747
- cumulusci_plus-5.0.24.dist-info/METADATA,sha256=rtDu9DsrrO68HBB5umhpTgg_h9lKA88pTPkpKi9ti4Y,6275
748
- cumulusci_plus-5.0.24.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
749
- cumulusci_plus-5.0.24.dist-info/entry_points.txt,sha256=nTtu04b9iLXhzADcTrb5PwmdXE6e2MTUAMh9OK6Z2pg,80
750
- cumulusci_plus-5.0.24.dist-info/licenses/AUTHORS.rst,sha256=PvewjKImdKPhhJ6xR2EEZ4T7GbpY2ZeAeyWm2aLtiMQ,676
751
- cumulusci_plus-5.0.24.dist-info/licenses/LICENSE,sha256=NFsF_s7RVXk2dU6tmRAN8wF45pnD98VZ5IwqOsyBcaU,1499
752
- cumulusci_plus-5.0.24.dist-info/RECORD,,
756
+ cumulusci_plus-5.0.25.dist-info/METADATA,sha256=AdvB-RjLPnMPh0NDEHk0hEc38RCVJu-eowsFn2MNCsg,6373
757
+ cumulusci_plus-5.0.25.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
758
+ cumulusci_plus-5.0.25.dist-info/entry_points.txt,sha256=nTtu04b9iLXhzADcTrb5PwmdXE6e2MTUAMh9OK6Z2pg,80
759
+ cumulusci_plus-5.0.25.dist-info/licenses/AUTHORS.rst,sha256=PvewjKImdKPhhJ6xR2EEZ4T7GbpY2ZeAeyWm2aLtiMQ,676
760
+ cumulusci_plus-5.0.25.dist-info/licenses/LICENSE,sha256=NFsF_s7RVXk2dU6tmRAN8wF45pnD98VZ5IwqOsyBcaU,1499
761
+ cumulusci_plus-5.0.25.dist-info/RECORD,,