Skip to content

Commit 77acbd9

Browse files
jsun-clariticoderabbitai[bot]dipakparmar
authored
DEVOPS-708 feat: add force_resolution_strategy option to update dependency task for install beta packages on sandbox orgs (#7)
* DEVOPS-708 feat: add force_resolution_strategy option to UpdateDependencies task for sandbox orgs * DEVOPS-708 refactor: remove debug logging for resolution strategy in UpdateDependencies task * DEVOPS-708 fix: remove extra space Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Signed-off-by: Jessica Sun <45977467+jsun-clariti@users.noreply.github.com> * DEVOPS-708 chore: correct typo Signed-off-by: Dipak Parmar <hi@dipak.tech> * DEVOP-708 refactor: remove unnecessary blank lines in test_org_import_rejects_username_and_pool_id * DEVOPS-708 refactor: improve resolver removal logic in UpdateDependencies task * DEVOPS-708 fix: update error message for SF alias failure in test_set_sf_alias_failure * DEVOPS-708 refactor: remove unnecessary logging in test_init_options_force_resolution_strategy_sandbox * DEVOPS-708 refactor: remove redundant checks Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Signed-off-by: Jessica Sun <45977467+jsun-clariti@users.noreply.github.com> --------- Signed-off-by: Jessica Sun <45977467+jsun-clariti@users.noreply.github.com> Signed-off-by: Dipak Parmar <hi@dipak.tech> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: Dipak Parmar <hi@dipak.tech>
1 parent cbf3bcf commit 77acbd9

5 files changed

Lines changed: 110 additions & 9 deletions

File tree

cumulusci/tasks/salesforce/tests/test_update_dependencies.py

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,83 @@ def test_init_options_removes_unsafe_resolvers_persistent_org():
186186
)
187187
task.org_config = mock.Mock()
188188
task.org_config.scratch = False
189+
task.org_config.is_sandbox = True
190+
191+
assert DependencyResolutionStrategy.BETA_RELEASE_TAG not in task.resolution_strategy
192+
assert (
193+
DependencyResolutionStrategy.COMMIT_STATUS_RELEASE_BRANCH
194+
not in task.resolution_strategy
195+
)
196+
197+
198+
def test_init_options_force_resolution_strategy_production():
199+
"""Test that force_resolution_strategy only checks safety for production orgs"""
200+
task = create_task(
201+
UpdateDependencies,
202+
{
203+
"dependencies": [
204+
{
205+
"namespace": "ns",
206+
"version": "1.0",
207+
}
208+
],
209+
"resolution_strategy": "include_beta",
210+
"force_resolution_strategy": True,
211+
},
212+
)
213+
task.org_config = mock.Mock()
214+
task.org_config.scratch = False
215+
task.org_config.is_sandbox = False # Production org
216+
217+
assert DependencyResolutionStrategy.BETA_RELEASE_TAG not in task.resolution_strategy
218+
assert (
219+
DependencyResolutionStrategy.COMMIT_STATUS_RELEASE_BRANCH
220+
not in task.resolution_strategy
221+
)
222+
223+
224+
def test_init_options_force_resolution_strategy_sandbox():
225+
"""Test that force_resolution_strategy allows unsafe resolvers in sandbox"""
226+
org_config = mock.Mock()
227+
org_config.scratch = False
228+
org_config.is_sandbox = True # Sandbox org
229+
task = create_task(
230+
UpdateDependencies,
231+
{
232+
"dependencies": [
233+
{
234+
"namespace": "ns",
235+
"version": "1.0",
236+
}
237+
],
238+
"resolution_strategy": "include_beta",
239+
"force_resolution_strategy": True,
240+
},
241+
project_config=None,
242+
org_config=org_config,
243+
)
244+
assert DependencyResolutionStrategy.BETA_RELEASE_TAG in task.resolution_strategy
245+
246+
247+
def test_init_options_force_resolution_strategy_false():
248+
"""Test that when force_resolution_strategy is False, safety checks apply to all persistent orgs"""
249+
org_config = mock.Mock()
250+
org_config.scratch = False
251+
org_config.is_sandbox = False # Production org
252+
task = create_task(
253+
UpdateDependencies,
254+
{
255+
"dependencies": [
256+
{
257+
"namespace": "ns",
258+
"version": "1.0",
259+
}
260+
],
261+
"resolution_strategy": "include_beta"
262+
},
263+
project_config=None,
264+
org_config=org_config,
265+
)
189266

190267
assert DependencyResolutionStrategy.BETA_RELEASE_TAG not in task.resolution_strategy
191268
assert (

cumulusci/tasks/salesforce/update_dependencies.py

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ class UpdateDependencies(BaseSalesforceTask):
6464
"base_package_url_format": {
6565
"description": "If `interactive` is set to True, display package Ids using a format string ({} will be replaced with the package Id)."
6666
},
67+
"force_resolution_strategy": {
68+
"description": "If True, forces the use of the specified resolution_strategy on scratch and sandbox orgs. Defaults to False."
69+
},
6770
**{k: v for k, v in PACKAGE_INSTALL_TASK_OPTIONS.items() if k != "password"},
6871
}
6972

@@ -138,18 +141,31 @@ def _init_options(self, kwargs):
138141
DependencyResolutionStrategy.BETA_RELEASE_TAG,
139142
]
140143

141-
if (
142-
self.org_config
143-
and not self.org_config.scratch
144-
and any(r in self.resolution_strategy for r in unsafe_prod_resolvers)
145-
):
144+
force_strategy = process_bool_arg(self.options.get("force_resolution_strategy", False))
145+
if force_strategy:
146+
self.logger.warning(
147+
"The force_resolution_strategy option is turned on and dependency resolution will be forced on scratch and sandbox orgs."
148+
)
149+
150+
# Only remove resolvers for:
151+
# 1. Non-scratch production orgs when force_strategy is True
152+
# 2. All non-scratch orgs when force_strategy is False
153+
should_remove_resolvers = (
154+
self.org_config # Have an org config
155+
and not self.org_config.scratch # Not a scratch org
156+
and (
157+
not force_strategy # Remove for all non-scratch orgs
158+
or (force_strategy and not self.org_config.is_sandbox) # Remove for production orgs only
159+
)
160+
)
161+
162+
if should_remove_resolvers and any(r in self.resolution_strategy for r in unsafe_prod_resolvers):
146163
self.logger.warning(
147164
"Target org is a persistent org; removing Beta resolvers. Consider selecting the `production` resolver stack."
148165
)
149166
self.resolution_strategy = [
150167
r for r in self.resolution_strategy if r not in unsafe_prod_resolvers
151168
]
152-
153169
if (
154170
"prefer_2gp_from_release_branch" in self.options
155171
or "include_beta" in self.options

cumulusci/tests/test_cli_org_import.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@ def _load_keychain(self):
1414
# Tests bypass actual keychain loading.
1515
pass
1616

17-
18-
def test_org_import_rejects_username_and_pool_id(tmp_path):
1917
def test_org_import_rejects_username_and_pool_id(tmp_path):
2018
runner = CliRunner()
2119
runtime = FakeRuntime()

cumulusci/tests/test_utils_clariti.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ def fake_run(command, check, text, capture_output, env):
180180
success, message = set_sf_alias("target", "username")
181181

182182
assert success is False
183-
assert message is not None and message.startswith("Clariti alias failed")
183+
assert message is not None and message.startswith("Failed to set SF alias")
184184
assert "Alias failure" in message
185185

186186

docs/config.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,16 @@ functionality to suit your project's specific needs.
4646
If you repeatedly specify the same value for an option while running a
4747
task, you can configure CumulusCI to use that value as a default value.
4848

49+
For example: Let's configure the update_dependencies task to force resolution strategies in sandbox orgs. The task's `force_resolution_strategy` option controls whether to force the use of specified resolution strategies even in persistent orgs:
50+
51+
```yaml
52+
update_dependencies:
53+
options:
54+
force_resolution_strategy: True
55+
```
56+
57+
When True, this allows beta and 2GP resolvers to be used in sandbox orgs, while still enforcing safety checks in production orgs. When False (default), safety checks are enforced in all persistent orgs.
58+
4959
For example: Let's enforce a 90% code coverage requirement for Apex
5060
code in your project. The `run_tests` task, which executes all Apex
5161
tests in a target org, can enforce code coverage at a given percentage

0 commit comments

Comments
 (0)