cumulusci-plus 5.0.21__py3-none-any.whl → 5.0.43__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.
Files changed (135) hide show
  1. cumulusci/__about__.py +1 -1
  2. cumulusci/cli/logger.py +2 -2
  3. cumulusci/cli/service.py +20 -0
  4. cumulusci/cli/task.py +19 -3
  5. cumulusci/cli/tests/test_error.py +3 -1
  6. cumulusci/cli/tests/test_flow.py +279 -2
  7. cumulusci/cli/tests/test_org.py +5 -0
  8. cumulusci/cli/tests/test_service.py +15 -12
  9. cumulusci/cli/tests/test_task.py +122 -2
  10. cumulusci/cli/tests/utils.py +1 -4
  11. cumulusci/core/config/__init__.py +1 -0
  12. cumulusci/core/config/base_task_flow_config.py +26 -1
  13. cumulusci/core/config/org_config.py +2 -1
  14. cumulusci/core/config/project_config.py +14 -20
  15. cumulusci/core/config/scratch_org_config.py +12 -0
  16. cumulusci/core/config/tests/test_config.py +1 -0
  17. cumulusci/core/config/tests/test_config_expensive.py +9 -3
  18. cumulusci/core/config/universal_config.py +3 -4
  19. cumulusci/core/dependencies/base.py +5 -1
  20. cumulusci/core/dependencies/dependencies.py +1 -1
  21. cumulusci/core/dependencies/github.py +1 -2
  22. cumulusci/core/dependencies/resolvers.py +1 -1
  23. cumulusci/core/dependencies/tests/test_dependencies.py +1 -1
  24. cumulusci/core/dependencies/tests/test_resolvers.py +1 -1
  25. cumulusci/core/flowrunner.py +90 -6
  26. cumulusci/core/github.py +1 -1
  27. cumulusci/core/sfdx.py +3 -1
  28. cumulusci/core/source_transforms/tests/test_transforms.py +1 -1
  29. cumulusci/core/source_transforms/transforms.py +1 -1
  30. cumulusci/core/tasks.py +13 -2
  31. cumulusci/core/tests/test_flowrunner.py +100 -0
  32. cumulusci/core/tests/test_tasks.py +65 -0
  33. cumulusci/core/utils.py +3 -1
  34. cumulusci/core/versions.py +1 -1
  35. cumulusci/cumulusci.yml +73 -1
  36. cumulusci/oauth/client.py +1 -1
  37. cumulusci/plugins/plugin_base.py +5 -3
  38. cumulusci/robotframework/pageobjects/ObjectManagerPageObject.py +1 -1
  39. cumulusci/salesforce_api/rest_deploy.py +1 -1
  40. cumulusci/schema/cumulusci.jsonschema.json +69 -0
  41. cumulusci/tasks/apex/anon.py +1 -1
  42. cumulusci/tasks/apex/testrunner.py +421 -144
  43. cumulusci/tasks/apex/tests/test_apex_tasks.py +917 -1
  44. cumulusci/tasks/bulkdata/extract.py +0 -1
  45. cumulusci/tasks/bulkdata/extract_dataset_utils/extract_yml.py +1 -1
  46. cumulusci/tasks/bulkdata/extract_dataset_utils/synthesize_extract_declarations.py +1 -1
  47. cumulusci/tasks/bulkdata/extract_dataset_utils/tests/test_extract_yml.py +1 -1
  48. cumulusci/tasks/bulkdata/generate_and_load_data.py +136 -12
  49. cumulusci/tasks/bulkdata/mapping_parser.py +139 -44
  50. cumulusci/tasks/bulkdata/select_utils.py +1 -1
  51. cumulusci/tasks/bulkdata/snowfakery.py +100 -25
  52. cumulusci/tasks/bulkdata/tests/test_generate_and_load.py +159 -0
  53. cumulusci/tasks/bulkdata/tests/test_load.py +0 -2
  54. cumulusci/tasks/bulkdata/tests/test_mapping_parser.py +763 -1
  55. cumulusci/tasks/bulkdata/tests/test_select_utils.py +46 -0
  56. cumulusci/tasks/bulkdata/tests/test_snowfakery.py +133 -0
  57. cumulusci/tasks/create_package_version.py +190 -16
  58. cumulusci/tasks/datadictionary.py +1 -1
  59. cumulusci/tasks/metadata_etl/__init__.py +2 -0
  60. cumulusci/tasks/metadata_etl/applications.py +256 -0
  61. cumulusci/tasks/metadata_etl/base.py +7 -3
  62. cumulusci/tasks/metadata_etl/layouts.py +1 -1
  63. cumulusci/tasks/metadata_etl/permissions.py +1 -1
  64. cumulusci/tasks/metadata_etl/remote_site_settings.py +2 -2
  65. cumulusci/tasks/metadata_etl/tests/test_applications.py +710 -0
  66. cumulusci/tasks/push/README.md +15 -17
  67. cumulusci/tasks/release_notes/README.md +13 -13
  68. cumulusci/tasks/release_notes/generator.py +13 -8
  69. cumulusci/tasks/robotframework/tests/test_robotframework.py +6 -1
  70. cumulusci/tasks/salesforce/Deploy.py +53 -2
  71. cumulusci/tasks/salesforce/SfPackageCommands.py +363 -0
  72. cumulusci/tasks/salesforce/__init__.py +1 -0
  73. cumulusci/tasks/salesforce/assign_ps_psg.py +448 -0
  74. cumulusci/tasks/salesforce/composite.py +1 -1
  75. cumulusci/tasks/salesforce/custom_settings_wait.py +1 -1
  76. cumulusci/tasks/salesforce/enable_prediction.py +5 -1
  77. cumulusci/tasks/salesforce/getPackageVersion.py +89 -0
  78. cumulusci/tasks/salesforce/insert_record.py +18 -19
  79. cumulusci/tasks/salesforce/sourcetracking.py +1 -1
  80. cumulusci/tasks/salesforce/tests/test_Deploy.py +316 -1
  81. cumulusci/tasks/salesforce/tests/test_SfPackageCommands.py +554 -0
  82. cumulusci/tasks/salesforce/tests/test_assign_ps_psg.py +1055 -0
  83. cumulusci/tasks/salesforce/tests/test_enable_prediction.py +4 -2
  84. cumulusci/tasks/salesforce/tests/test_getPackageVersion.py +651 -0
  85. cumulusci/tasks/salesforce/tests/test_update_dependencies.py +1 -1
  86. cumulusci/tasks/salesforce/tests/test_update_external_auth_identity_provider.py +927 -0
  87. cumulusci/tasks/salesforce/tests/test_update_external_credential.py +1427 -0
  88. cumulusci/tasks/salesforce/tests/test_update_named_credential.py +1042 -0
  89. cumulusci/tasks/salesforce/tests/test_update_record.py +512 -0
  90. cumulusci/tasks/salesforce/update_dependencies.py +2 -2
  91. cumulusci/tasks/salesforce/update_external_auth_identity_provider.py +551 -0
  92. cumulusci/tasks/salesforce/update_external_credential.py +647 -0
  93. cumulusci/tasks/salesforce/update_named_credential.py +441 -0
  94. cumulusci/tasks/salesforce/update_profile.py +17 -13
  95. cumulusci/tasks/salesforce/update_record.py +217 -0
  96. cumulusci/tasks/salesforce/users/permsets.py +62 -5
  97. cumulusci/tasks/salesforce/users/tests/test_permsets.py +237 -11
  98. cumulusci/tasks/sfdmu/__init__.py +0 -0
  99. cumulusci/tasks/sfdmu/sfdmu.py +376 -0
  100. cumulusci/tasks/sfdmu/tests/__init__.py +1 -0
  101. cumulusci/tasks/sfdmu/tests/test_runner.py +212 -0
  102. cumulusci/tasks/sfdmu/tests/test_sfdmu.py +1012 -0
  103. cumulusci/tasks/tests/test_create_package_version.py +716 -1
  104. cumulusci/tasks/tests/test_util.py +42 -0
  105. cumulusci/tasks/util.py +37 -1
  106. cumulusci/tasks/utility/copyContents.py +402 -0
  107. cumulusci/tasks/utility/credentialManager.py +302 -0
  108. cumulusci/tasks/utility/directoryRecreator.py +30 -0
  109. cumulusci/tasks/utility/env_management.py +1 -1
  110. cumulusci/tasks/utility/secretsToEnv.py +135 -0
  111. cumulusci/tasks/utility/tests/test_copyContents.py +1719 -0
  112. cumulusci/tasks/utility/tests/test_credentialManager.py +1150 -0
  113. cumulusci/tasks/utility/tests/test_directoryRecreator.py +439 -0
  114. cumulusci/tasks/utility/tests/test_secretsToEnv.py +1118 -0
  115. cumulusci/tests/test_integration_infrastructure.py +3 -1
  116. cumulusci/tests/test_utils.py +70 -6
  117. cumulusci/utils/__init__.py +54 -9
  118. cumulusci/utils/classutils.py +5 -2
  119. cumulusci/utils/http/tests/cassettes/ManualEditTestCompositeParallelSalesforce.test_http_headers.yaml +31 -30
  120. cumulusci/utils/options.py +23 -1
  121. cumulusci/utils/parallel/task_worker_queues/parallel_worker.py +1 -1
  122. cumulusci/utils/yaml/cumulusci_yml.py +8 -3
  123. cumulusci/utils/yaml/model_parser.py +2 -2
  124. cumulusci/utils/yaml/tests/test_cumulusci_yml.py +1 -1
  125. cumulusci/utils/yaml/tests/test_model_parser.py +3 -3
  126. cumulusci/vcs/base.py +23 -15
  127. cumulusci/vcs/bootstrap.py +5 -4
  128. cumulusci/vcs/utils/list_modified_files.py +189 -0
  129. cumulusci/vcs/utils/tests/test_list_modified_files.py +588 -0
  130. {cumulusci_plus-5.0.21.dist-info → cumulusci_plus-5.0.43.dist-info}/METADATA +11 -10
  131. {cumulusci_plus-5.0.21.dist-info → cumulusci_plus-5.0.43.dist-info}/RECORD +135 -104
  132. {cumulusci_plus-5.0.21.dist-info → cumulusci_plus-5.0.43.dist-info}/WHEEL +1 -1
  133. {cumulusci_plus-5.0.21.dist-info → cumulusci_plus-5.0.43.dist-info}/entry_points.txt +0 -0
  134. {cumulusci_plus-5.0.21.dist-info → cumulusci_plus-5.0.43.dist-info}/licenses/AUTHORS.rst +0 -0
  135. {cumulusci_plus-5.0.21.dist-info → cumulusci_plus-5.0.43.dist-info}/licenses/LICENSE +0 -0
@@ -1,10 +1,11 @@
1
1
  import json
2
- from unittest.mock import patch
2
+ from unittest import mock
3
3
 
4
4
  import pytest
5
5
  import responses
6
6
  from responses.matchers import json_params_matcher
7
7
 
8
+ from cumulusci.core.config.org_config import OrgConfig
8
9
  from cumulusci.core.exceptions import CumulusCIException
9
10
  from cumulusci.tasks.salesforce.tests.util import create_task
10
11
  from cumulusci.tasks.salesforce.users.permsets import (
@@ -12,7 +13,11 @@ from cumulusci.tasks.salesforce.users.permsets import (
12
13
  AssignPermissionSetLicenses,
13
14
  AssignPermissionSets,
14
15
  )
15
- from cumulusci.tests.util import CURRENT_SF_API_VERSION
16
+ from cumulusci.tests.util import (
17
+ CURRENT_SF_API_VERSION,
18
+ DummyKeychain,
19
+ create_project_config,
20
+ )
16
21
 
17
22
 
18
23
  class TestCreatePermissionSet:
@@ -46,7 +51,7 @@ class TestCreatePermissionSet:
46
51
  )
47
52
  responses.add(
48
53
  method="GET",
49
- url=f"{task.org_config.instance_url}/services/data/v{CURRENT_SF_API_VERSION}/query/?q=SELECT+Id%2CName+FROM+PermissionSet+WHERE+Name+IN+%28%27PermSet1%27%2C+%27PermSet2%27%29",
54
+ url=f"{task.org_config.instance_url}/services/data/v{CURRENT_SF_API_VERSION}/query/?q=SELECT+Id%2C+NamespacePrefix%2C+Name+FROM+PermissionSet+WHERE+%28Name+%3D+%27PermSet1%27+OR+Name+%3D+%27PermSet2%27%29",
50
55
  status=200,
51
56
  json={
52
57
  "done": True,
@@ -55,10 +60,12 @@ class TestCreatePermissionSet:
55
60
  {
56
61
  "Id": "0PS000000000000",
57
62
  "Name": "PermSet1",
63
+ "NamespacePrefix": None,
58
64
  },
59
65
  {
60
66
  "Id": "0PS000000000001",
61
67
  "Name": "PermSet2",
68
+ "NamespacePrefix": None,
62
69
  },
63
70
  ],
64
71
  },
@@ -127,7 +134,7 @@ class TestCreatePermissionSet:
127
134
  )
128
135
  responses.add(
129
136
  method="GET",
130
- url=f"{task.org_config.instance_url}/services/data/v{CURRENT_SF_API_VERSION}/query/?q=SELECT+Id%2CName+FROM+PermissionSet+WHERE+Name+IN+%28%27PermSet1%27%2C+%27PermSet2%27%29",
137
+ url=f"{task.org_config.instance_url}/services/data/v{CURRENT_SF_API_VERSION}/query/?q=SELECT+Id%2C+NamespacePrefix%2C+Name+FROM+PermissionSet+WHERE+%28Name+%3D+%27PermSet1%27+OR+Name+%3D+%27PermSet2%27%29",
131
138
  status=200,
132
139
  json={
133
140
  "done": True,
@@ -136,10 +143,12 @@ class TestCreatePermissionSet:
136
143
  {
137
144
  "Id": "0PS000000000000",
138
145
  "Name": "PermSet1",
146
+ "NamespacePrefix": None,
139
147
  },
140
148
  {
141
149
  "Id": "0PS000000000001",
142
150
  "Name": "PermSet2",
151
+ "NamespacePrefix": None,
143
152
  },
144
153
  ],
145
154
  },
@@ -228,7 +237,7 @@ class TestCreatePermissionSet:
228
237
  )
229
238
  responses.add(
230
239
  method="GET",
231
- url=f"{task.org_config.instance_url}/services/data/v{CURRENT_SF_API_VERSION}/query/?q=SELECT+Id%2CName+FROM+PermissionSet+WHERE+Name+IN+%28%27PermSet0%27%2C+%27PermSet1%27%2C+%27PermSet2%27%2C+%27PermSet3%27%2C+%27PermSet4%27%2C+%27PermSet5%27%2C+%27PermSet6%27%2C+%27PermSet7%27%2C+%27PermSet8%27%2C+%27PermSet9%27%2C+%27PermSet10%27%2C+%27PermSet11%27%2C+%27PermSet12%27%2C+%27PermSet13%27%2C+%27PermSet14%27%2C+%27PermSet15%27%2C+%27PermSet16%27%2C+%27PermSet17%27%2C+%27PermSet18%27%2C+%27PermSet19%27%29",
240
+ url=f"{task.org_config.instance_url}/services/data/v{CURRENT_SF_API_VERSION}/query/?q=SELECT+Id%2C+NamespacePrefix%2C+Name+FROM+PermissionSet+WHERE+%28Name+%3D+%27PermSet0%27+OR+Name+%3D+%27PermSet1%27+OR+Name+%3D+%27PermSet2%27+OR+Name+%3D+%27PermSet3%27+OR+Name+%3D+%27PermSet4%27+OR+Name+%3D+%27PermSet5%27+OR+Name+%3D+%27PermSet6%27+OR+Name+%3D+%27PermSet7%27+OR+Name+%3D+%27PermSet8%27+OR+Name+%3D+%27PermSet9%27+OR+Name+%3D+%27PermSet10%27+OR+Name+%3D+%27PermSet11%27+OR+Name+%3D+%27PermSet12%27+OR+Name+%3D+%27PermSet13%27+OR+Name+%3D+%27PermSet14%27+OR+Name+%3D+%27PermSet15%27+OR+Name+%3D+%27PermSet16%27+OR+Name+%3D+%27PermSet17%27+OR+Name+%3D+%27PermSet18%27+OR+Name+%3D+%27PermSet19%27%29",
232
241
  status=200,
233
242
  json={
234
243
  "done": True,
@@ -237,6 +246,7 @@ class TestCreatePermissionSet:
237
246
  {
238
247
  "Id": f"0PS000000000000{str(i)}",
239
248
  "Name": f"PermSet{str(i)}",
249
+ "NamespacePrefix": None,
240
250
  }
241
251
  for i in range(20)
242
252
  ],
@@ -288,7 +298,7 @@ class TestCreatePermissionSet:
288
298
  )
289
299
  responses.add(
290
300
  method="GET",
291
- url=f"{task.org_config.instance_url}/services/data/v{CURRENT_SF_API_VERSION}/query/?q=SELECT+Id%2CName+FROM+PermissionSet+WHERE+Name+IN+%28%27PermSet1%27%2C+%27PermSet2%27%2C+%27PermSet3%27%29",
301
+ url=f"{task.org_config.instance_url}/services/data/v{CURRENT_SF_API_VERSION}/query/?q=SELECT+Id%2C+NamespacePrefix%2C+Name+FROM+PermissionSet+WHERE+%28Name+%3D+%27PermSet1%27+OR+Name+%3D+%27PermSet2%27+OR+Name+%3D+%27PermSet3%27%29",
292
302
  status=200,
293
303
  json={
294
304
  "done": True,
@@ -297,10 +307,12 @@ class TestCreatePermissionSet:
297
307
  {
298
308
  "Id": "0PS000000000000",
299
309
  "Name": "PermSet1",
310
+ "NamespacePrefix": None,
300
311
  },
301
312
  {
302
313
  "Id": "0PS000000000001",
303
314
  "Name": "PermSet2",
315
+ "NamespacePrefix": None,
304
316
  },
305
317
  ],
306
318
  },
@@ -310,7 +322,7 @@ class TestCreatePermissionSet:
310
322
  task()
311
323
 
312
324
  @responses.activate
313
- @patch("cumulusci.tasks.salesforce.users.permsets.CliTable", autospec=True)
325
+ @mock.patch("cumulusci.tasks.salesforce.users.permsets.CliTable", autospec=True)
314
326
  def test_create_permset_partial_success_raises(self, table):
315
327
  task = create_task(
316
328
  AssignPermissionSets,
@@ -349,7 +361,7 @@ class TestCreatePermissionSet:
349
361
  )
350
362
  responses.add(
351
363
  method="GET",
352
- url=f"{task.org_config.instance_url}/services/data/v{CURRENT_SF_API_VERSION}/query/?q=SELECT+Id%2CName+FROM+PermissionSet+WHERE+Name+IN+%28%27PermSet1%27%2C+%27PermSet2%27%29",
364
+ url=f"{task.org_config.instance_url}/services/data/v{CURRENT_SF_API_VERSION}/query/?q=SELECT+Id%2C+NamespacePrefix%2C+Name+FROM+PermissionSet+WHERE+%28Name+%3D+%27PermSet1%27+OR+Name+%3D+%27PermSet2%27%29",
353
365
  status=200,
354
366
  json={
355
367
  "done": True,
@@ -358,10 +370,12 @@ class TestCreatePermissionSet:
358
370
  {
359
371
  "Id": "0PS000000000000",
360
372
  "Name": "PermSet1",
373
+ "NamespacePrefix": None,
361
374
  },
362
375
  {
363
376
  "Id": "0PS000000000001",
364
377
  "Name": "PermSet2",
378
+ "NamespacePrefix": None,
365
379
  },
366
380
  ],
367
381
  },
@@ -416,6 +430,212 @@ class TestCreatePermissionSet:
416
430
  table.assert_called_once()
417
431
  assert expected_table_data in table.call_args[0]
418
432
 
433
+ @responses.activate
434
+ def test_namespace_injection_managed(self):
435
+ """Test that %%%NAMESPACE%%% token gets replaced in managed context"""
436
+ task = create_task(
437
+ AssignPermissionSets,
438
+ {
439
+ "api_names": "%%%NAMESPACE%%%PermSet1,PermSet2",
440
+ "namespace_inject": "testns",
441
+ "managed": True,
442
+ },
443
+ )
444
+ # Simulate managed context by setting the namespace in project config
445
+ task.project_config.config["project"]["package"]["namespace"] = "testns"
446
+ # Simulate that the package is installed (managed mode)
447
+ task.org_config._installed_packages = {"testns": "1.0"}
448
+ task.org_config.namespace = None # Not a packaging org
449
+
450
+ responses.add(
451
+ method="GET",
452
+ url=f"{task.org_config.instance_url}/services/data/v{CURRENT_SF_API_VERSION}/query/?q=SELECT+Id%2C%28SELECT+PermissionSetId+FROM+PermissionSetAssignments%29+FROM+User+WHERE+Username+%3D+%27test-cci%40example.com%27",
453
+ status=200,
454
+ json={
455
+ "done": True,
456
+ "totalSize": 1,
457
+ "records": [
458
+ {
459
+ "Id": "005000000000000",
460
+ "PermissionSetAssignments": None,
461
+ }
462
+ ],
463
+ },
464
+ )
465
+ responses.add(
466
+ method="GET",
467
+ url=f"{task.org_config.instance_url}/services/data/v{CURRENT_SF_API_VERSION}/query/?q=SELECT+Id%2C+NamespacePrefix%2C+Name+FROM+PermissionSet+WHERE+%28%28NamespacePrefix+%3D+%27testns%27+AND+Name+%3D+%27PermSet1%27%29+OR+Name+%3D+%27PermSet2%27%29",
468
+ status=200,
469
+ json={
470
+ "done": True,
471
+ "totalSize": 2,
472
+ "records": [
473
+ {
474
+ "Id": "0PS000000000000",
475
+ "Name": "PermSet1",
476
+ "NamespacePrefix": "testns",
477
+ },
478
+ {
479
+ "Id": "0PS000000000001",
480
+ "Name": "PermSet2",
481
+ "NamespacePrefix": None,
482
+ },
483
+ ],
484
+ },
485
+ )
486
+ responses.add(
487
+ method="POST",
488
+ url=f"{task.org_config.instance_url}/services/data/v{CURRENT_SF_API_VERSION}/composite/sobjects",
489
+ status=200,
490
+ json=[
491
+ {"id": "0Pa000000000000", "success": True, "errors": []},
492
+ {"id": "0Pa000000000001", "success": True, "errors": []},
493
+ ],
494
+ )
495
+
496
+ task()
497
+
498
+ assert len(responses.calls) == 3
499
+ # Verify that the SOQL query contains the namespaced permission set name with namespace prefix condition
500
+ assert (
501
+ "NamespacePrefix+%3D+%27testns%27+AND+Name+%3D+%27PermSet1%27"
502
+ in responses.calls[1].request.url
503
+ )
504
+
505
+ @responses.activate
506
+ def test_namespace_injection_unmanaged(self):
507
+ """Test that %%%NAMESPACE%%% token gets stripped in unmanaged context"""
508
+ task = create_task(
509
+ AssignPermissionSets,
510
+ {
511
+ "api_names": "%%%NAMESPACE%%%PermSet1",
512
+ },
513
+ )
514
+ # Simulate unmanaged context (scratch org) - no installed packages
515
+ task.project_config.config["project"]["package"]["namespace"] = "testns"
516
+ task.org_config._installed_packages = {}
517
+ task.org_config.namespace = None # Not a packaging org
518
+
519
+ responses.add(
520
+ method="GET",
521
+ url=f"{task.org_config.instance_url}/services/data/v{CURRENT_SF_API_VERSION}/query/?q=SELECT+Id%2C%28SELECT+PermissionSetId+FROM+PermissionSetAssignments%29+FROM+User+WHERE+Username+%3D+%27test-cci%40example.com%27",
522
+ status=200,
523
+ json={
524
+ "done": True,
525
+ "totalSize": 1,
526
+ "records": [
527
+ {
528
+ "Id": "005000000000000",
529
+ "PermissionSetAssignments": None,
530
+ }
531
+ ],
532
+ },
533
+ )
534
+ responses.add(
535
+ method="GET",
536
+ url=f"{task.org_config.instance_url}/services/data/v{CURRENT_SF_API_VERSION}/query/?q=SELECT+Id%2C+NamespacePrefix%2C+Name+FROM+PermissionSet+WHERE+%28Name+%3D+%27PermSet1%27%29",
537
+ status=200,
538
+ json={
539
+ "done": True,
540
+ "totalSize": 1,
541
+ "records": [
542
+ {
543
+ "Id": "0PS000000000000",
544
+ "Name": "PermSet1",
545
+ "NamespacePrefix": None,
546
+ },
547
+ ],
548
+ },
549
+ )
550
+ responses.add(
551
+ method="POST",
552
+ url=f"{task.org_config.instance_url}/services/data/v{CURRENT_SF_API_VERSION}/composite/sobjects",
553
+ status=200,
554
+ json=[
555
+ {"id": "0Pa000000000000", "success": True, "errors": []},
556
+ ],
557
+ )
558
+
559
+ task()
560
+
561
+ assert len(responses.calls) == 3
562
+ # Verify that the SOQL query does NOT contain the namespace prefix
563
+ assert "testns__" not in responses.calls[1].request.url
564
+ assert "PermSet1" in responses.calls[1].request.url
565
+
566
+ @responses.activate
567
+ def test_namespaced_org_token(self):
568
+ """Test that %%%NAMESPACED_ORG%%% token gets replaced in namespaced org context"""
569
+ org_config = OrgConfig(
570
+ {
571
+ "instance_url": "https://test.salesforce.com",
572
+ "id": "https://test.salesforce.com/ORG_ID/USER_ID",
573
+ "access_token": "TOKEN",
574
+ "org_id": "ORG_ID",
575
+ "username": "test-cci@example.com",
576
+ "namespace": "testns",
577
+ },
578
+ "test",
579
+ keychain=DummyKeychain(),
580
+ )
581
+ org_config.refresh_oauth_token = mock.Mock()
582
+ task = create_task(
583
+ AssignPermissionSets,
584
+ {
585
+ "api_names": "%%%NAMESPACED_ORG%%%PermSet1",
586
+ },
587
+ project_config=create_project_config(
588
+ "TestRepo", "TestOwner", namespace="testns"
589
+ ),
590
+ org_config=org_config,
591
+ )
592
+
593
+ responses.add(
594
+ method="GET",
595
+ url=f"{task.org_config.instance_url}/services/data/v{CURRENT_SF_API_VERSION}/query/?q=SELECT+Id%2C%28SELECT+PermissionSetId+FROM+PermissionSetAssignments%29+FROM+User+WHERE+Username+%3D+%27test-cci%40example.com%27",
596
+ status=200,
597
+ json={
598
+ "done": True,
599
+ "totalSize": 1,
600
+ "records": [
601
+ {
602
+ "Id": "005000000000000",
603
+ "PermissionSetAssignments": None,
604
+ }
605
+ ],
606
+ },
607
+ )
608
+ responses.add(
609
+ method="GET",
610
+ url=f"{task.org_config.instance_url}/services/data/v{CURRENT_SF_API_VERSION}/query/?q=SELECT+Id%2C+NamespacePrefix%2C+Name+FROM+PermissionSet+WHERE+%28%28NamespacePrefix+%3D+%27testns%27+AND+Name+%3D+%27PermSet1%27%29%29",
611
+ status=200,
612
+ json={
613
+ "done": True,
614
+ "totalSize": 1,
615
+ "records": [
616
+ {
617
+ "Id": "0PS000000000000",
618
+ "Name": "PermSet1",
619
+ "NamespacePrefix": "testns",
620
+ },
621
+ ],
622
+ },
623
+ )
624
+ responses.add(
625
+ method="POST",
626
+ url=f"{task.org_config.instance_url}/services/data/v{CURRENT_SF_API_VERSION}/composite/sobjects",
627
+ status=200,
628
+ json=[
629
+ {"id": "0Pa000000000000", "success": True, "errors": []},
630
+ ],
631
+ )
632
+
633
+ task()
634
+
635
+ assert len(responses.calls) == 3
636
+ # Verify that the SOQL query contains the namespaced permission set name
637
+ assert "PermSet1" in responses.calls[1].request.url
638
+
419
639
 
420
640
  class TestCreatePermissionSetLicense:
421
641
  @responses.activate
@@ -760,7 +980,7 @@ class TestCreatePermissionSetGroup:
760
980
  )
761
981
  responses.add(
762
982
  method="GET",
763
- url=f"{task.org_config.instance_url}/services/data/v{CURRENT_SF_API_VERSION}/query/?q=SELECT+Id%2CDeveloperName+FROM+PermissionSetGroup+WHERE+DeveloperName+IN+%28%27PermSetGroup1%27%2C+%27PermSetGroup2%27%29",
983
+ url=f"{task.org_config.instance_url}/services/data/v{CURRENT_SF_API_VERSION}/query/?q=SELECT+Id%2C+NamespacePrefix%2C+DeveloperName+FROM+PermissionSetGroup+WHERE+%28DeveloperName+%3D+%27PermSetGroup1%27+OR+DeveloperName+%3D+%27PermSetGroup2%27%29",
764
984
  status=200,
765
985
  json={
766
986
  "done": True,
@@ -769,10 +989,12 @@ class TestCreatePermissionSetGroup:
769
989
  {
770
990
  "Id": "0PG000000000000",
771
991
  "DeveloperName": "PermSetGroup1",
992
+ "NamespacePrefix": None,
772
993
  },
773
994
  {
774
995
  "Id": "0PG000000000001",
775
996
  "DeveloperName": "PermSetGroup2",
997
+ "NamespacePrefix": None,
776
998
  },
777
999
  ],
778
1000
  },
@@ -833,7 +1055,7 @@ class TestCreatePermissionSetGroup:
833
1055
  )
834
1056
  responses.add(
835
1057
  method="GET",
836
- url=f"{task.org_config.instance_url}/services/data/v{CURRENT_SF_API_VERSION}/query/?q=SELECT+Id%2CDeveloperName+FROM+PermissionSetGroup+WHERE+DeveloperName+IN+%28%27PermSetGroup1%27%2C+%27PermSetGroup2%27%29",
1058
+ url=f"{task.org_config.instance_url}/services/data/v{CURRENT_SF_API_VERSION}/query/?q=SELECT+Id%2C+NamespacePrefix%2C+DeveloperName+FROM+PermissionSetGroup+WHERE+%28DeveloperName+%3D+%27PermSetGroup1%27+OR+DeveloperName+%3D+%27PermSetGroup2%27%29",
837
1059
  status=200,
838
1060
  json={
839
1061
  "done": True,
@@ -842,10 +1064,12 @@ class TestCreatePermissionSetGroup:
842
1064
  {
843
1065
  "Id": "0PG000000000000",
844
1066
  "DeveloperName": "PermSetGroup1",
1067
+ "NamespacePrefix": None,
845
1068
  },
846
1069
  {
847
1070
  "Id": "0PG000000000001",
848
1071
  "DeveloperName": "PermSetGroup2",
1072
+ "NamespacePrefix": None,
849
1073
  },
850
1074
  ],
851
1075
  },
@@ -928,7 +1152,7 @@ class TestCreatePermissionSetGroup:
928
1152
  )
929
1153
  responses.add(
930
1154
  method="GET",
931
- url=f"{task.org_config.instance_url}/services/data/v{CURRENT_SF_API_VERSION}/query/?q=SELECT+Id%2CDeveloperName+FROM+PermissionSetGroup+WHERE+DeveloperName+IN+%28%27PermSetGroup1%27%2C+%27PermSetGroup2%27%2C+%27PermSetGroup3%27%29",
1155
+ url=f"{task.org_config.instance_url}/services/data/v{CURRENT_SF_API_VERSION}/query/?q=SELECT+Id%2C+NamespacePrefix%2C+DeveloperName+FROM+PermissionSetGroup+WHERE+%28DeveloperName+%3D+%27PermSetGroup1%27+OR+DeveloperName+%3D+%27PermSetGroup2%27+OR+DeveloperName+%3D+%27PermSetGroup3%27%29",
932
1156
  status=200,
933
1157
  json={
934
1158
  "done": True,
@@ -937,10 +1161,12 @@ class TestCreatePermissionSetGroup:
937
1161
  {
938
1162
  "Id": "0PG000000000000",
939
1163
  "DeveloperName": "PermSetGroup1",
1164
+ "NamespacePrefix": None,
940
1165
  },
941
1166
  {
942
1167
  "Id": "0PG000000000001",
943
1168
  "DeveloperName": "PermSetGroup2",
1169
+ "NamespacePrefix": None,
944
1170
  },
945
1171
  ],
946
1172
  },
File without changes