Skip to content

Commit 21d3cd3

Browse files
authored
fix: clean bulk_publish flags when deploy complete (#272)
1 parent e8a91cd commit 21d3cd3

3 files changed

Lines changed: 90 additions & 23 deletions

File tree

requirements-dev.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ argcomplete>=3.6.2
1111
psutil==7.0.0
1212
requests
1313
cryptography
14-
fabric-cicd>=1.2.0
14+
fabric-cicd>=1.3.0
1515

1616
# Testing and Building Requirements
1717
tox>=4.20.0

src/fabric_cli/commands/fs/deploy/fab_fs_deploy_config_file.py

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,13 @@
44
import json
55
from argparse import Namespace
66

7-
from fabric_cicd import append_feature_flag, configure_external_file_logging, deploy_with_config, disable_file_logging # type: ignore
7+
from fabric_cicd import ( # type: ignore
8+
append_feature_flag,
9+
configure_external_file_logging,
10+
deploy_with_config,
11+
disable_file_logging,
12+
remove_feature_flag,
13+
)
814

915
from fabric_cli.core import fab_constant, fab_state_config
1016
from fabric_cli.core import fab_logger
@@ -37,8 +43,7 @@ def deploy_with_config_file(args: Namespace) -> None:
3743
for param in deploy_parameters:
3844
if isinstance(deploy_parameters[param], str):
3945
try:
40-
deploy_parameters[param] = json.loads(
41-
deploy_parameters[param])
46+
deploy_parameters[param] = json.loads(deploy_parameters[param])
4247
except json.JSONDecodeError:
4348
# If it's not a valid JSON string, keep it as is
4449
pass
@@ -51,17 +56,20 @@ def deploy_with_config_file(args: Namespace) -> None:
5156
config_file_path=deploy_config_file,
5257
environment=args.target_env,
5358
token_credential=create_fabric_token_credential(), # MSAL bridge TokenCredential
54-
**deploy_parameters
59+
**deploy_parameters,
5560
)
5661

5762
if result:
58-
fab_ui.print_output_format(
59-
args, message=result.message)
63+
fab_ui.print_output_format(args, message=result.message)
6064

6165
except Exception as e:
6266
raise FabricCLIError(
63-
f"Deployment failed: {str(e)}",
64-
fab_constant.ERROR_IN_DEPLOYMENT)
67+
f"Deployment failed: {str(e)}", fab_constant.ERROR_IN_DEPLOYMENT
68+
)
69+
finally:
70+
bulk_publish_enabled = getattr(args, "bulk_publish", False)
71+
if bulk_publish_enabled:
72+
_remove_bulk_publish_feature_flags()
6573

6674

6775
def _apply_bulk_publish_feature_flags(args: Namespace) -> None:
@@ -82,3 +90,9 @@ def _apply_bulk_publish_feature_flags(args: Namespace) -> None:
8290
"fabric-cicd and may change or fail; omit the '--bulk_publish' flag "
8391
"to use standard per-item publish."
8492
)
93+
94+
95+
def _remove_bulk_publish_feature_flags() -> None:
96+
"""Remove command-scoped bulk publish flags from fabric-cicd global state."""
97+
remove_feature_flag("enable_experimental_features")
98+
remove_feature_flag("enable_bulk_publish")

tests/test_utils/test_fab_deploy_bulk_publish.py

Lines changed: 67 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33

44
from unittest.mock import patch
55

6+
import pytest
7+
8+
from fabric_cli.core.fab_exceptions import FabricCLIError
9+
610

711
class TestDeployBulkPublish:
812
"""
@@ -11,27 +15,30 @@ class TestDeployBulkPublish:
1115
HTTP cassettes.
1216
"""
1317

14-
def _run_deploy(self, tmp_path, bulk_publish, mock_fab_set_state_config):
15-
"""Invoke deploy_with_config_file with fabric-cicd mocked, returning the
16-
append_feature_flag mock for assertions."""
18+
def _create_deploy_args(self, tmp_path, bulk_publish):
19+
"""Create arguments for deploy_with_config_file."""
1720
from argparse import Namespace
1821

19-
import fabric_cli.commands.fs.deploy.fab_fs_deploy_config_file as deploy_mod
20-
from fabric_cli.core import fab_constant
21-
22-
# disable debug mode so fabric-cicd file logging is disabled during the run
23-
mock_fab_set_state_config(fab_constant.FAB_DEBUG_ENABLED, "false")
24-
25-
args = Namespace(
22+
return Namespace(
2623
config=str(tmp_path / "config.yml"),
2724
target_env="dev",
2825
params=None,
2926
bulk_publish=bulk_publish,
3027
command_path="deploy",
3128
)
3229

30+
def _run_deploy_success(self, tmp_path, bulk_publish, mock_fab_set_state_config):
31+
"""Run a successful deployment and return feature flag mocks."""
32+
import fabric_cli.commands.fs.deploy.fab_fs_deploy_config_file as deploy_mod
33+
from fabric_cli.core import fab_constant
34+
35+
# disable debug mode so fabric-cicd file logging is disabled during the run
36+
mock_fab_set_state_config(fab_constant.FAB_DEBUG_ENABLED, "false")
37+
args = self._create_deploy_args(tmp_path, bulk_publish)
38+
3339
with (
3440
patch.object(deploy_mod, "append_feature_flag") as mock_flag,
41+
patch.object(deploy_mod, "remove_feature_flag") as mock_remove_flag,
3542
patch.object(deploy_mod, "deploy_with_config", return_value=None),
3643
patch.object(deploy_mod, "disable_file_logging"),
3744
patch.object(deploy_mod, "configure_external_file_logging"),
@@ -41,28 +48,74 @@ def _run_deploy(self, tmp_path, bulk_publish, mock_fab_set_state_config):
4148
):
4249
deploy_mod.deploy_with_config_file(args)
4350

44-
return mock_flag
51+
return mock_flag, mock_remove_flag
52+
53+
def _run_deploy_failure(self, tmp_path, bulk_publish, mock_fab_set_state_config):
54+
"""Run a failed deployment and return feature flag mocks."""
55+
import fabric_cli.commands.fs.deploy.fab_fs_deploy_config_file as deploy_mod
56+
from fabric_cli.core import fab_constant
57+
58+
# disable debug mode so fabric-cicd file logging is disabled during the run
59+
mock_fab_set_state_config(fab_constant.FAB_DEBUG_ENABLED, "false")
60+
args = self._create_deploy_args(tmp_path, bulk_publish)
61+
62+
with (
63+
patch.object(deploy_mod, "append_feature_flag") as mock_flag,
64+
patch.object(deploy_mod, "remove_feature_flag") as mock_remove_flag,
65+
patch.object(
66+
deploy_mod,
67+
"deploy_with_config",
68+
side_effect=Exception("Simulated deployment failure"),
69+
),
70+
patch.object(deploy_mod, "disable_file_logging"),
71+
patch.object(deploy_mod, "configure_external_file_logging"),
72+
patch.object(
73+
deploy_mod, "create_fabric_token_credential", return_value=None
74+
),
75+
):
76+
with pytest.raises(FabricCLIError):
77+
deploy_mod.deploy_with_config_file(args)
78+
79+
return mock_flag, mock_remove_flag
4580

4681
def test_deploy_bulk_publish_enabled_appends_experimental_flags_success(
4782
self, tmp_path, mock_fab_set_state_config
4883
):
4984
"""When --bulk_publish is set, both experimental bulk publish flags are appended."""
50-
mock_flag = self._run_deploy(tmp_path, True, mock_fab_set_state_config)
85+
mock_flag, mock_remove_flag = self._run_deploy_success(
86+
tmp_path, True, mock_fab_set_state_config
87+
)
5188

5289
appended = [call.args[0] for call in mock_flag.call_args_list]
5390
assert "enable_experimental_features" in appended
5491
assert "enable_bulk_publish" in appended
5592
# existing behavior is preserved
5693
assert "disable_print_identity" in appended
94+
removed = [call.args[0] for call in mock_remove_flag.call_args_list]
95+
assert removed == ["enable_experimental_features", "enable_bulk_publish"]
96+
97+
def test_deploy_bulk_publish_enabled_removes_flags_on_failure(
98+
self, tmp_path, mock_fab_set_state_config
99+
):
100+
"""Bulk publish flags are removed when deployment raises an exception."""
101+
_, mock_remove_flag = self._run_deploy_failure(
102+
tmp_path, True, mock_fab_set_state_config
103+
)
104+
105+
removed = [call.args[0] for call in mock_remove_flag.call_args_list]
106+
assert removed == ["enable_experimental_features", "enable_bulk_publish"]
57107

58108
def test_deploy_bulk_publish_disabled_by_default_omits_flags_success(
59109
self, tmp_path, mock_fab_set_state_config
60110
):
61-
"""When --bulk_publish is not set (default), bulk publish flags are not appended."""
62-
mock_flag = self._run_deploy(tmp_path, False, mock_fab_set_state_config)
111+
"""When --bulk_publish is not set, bulk publish flags are not changed."""
112+
mock_flag, mock_remove_flag = self._run_deploy_success(
113+
tmp_path, False, mock_fab_set_state_config
114+
)
63115

64116
appended = [call.args[0] for call in mock_flag.call_args_list]
65117
assert "enable_experimental_features" not in appended
66118
assert "enable_bulk_publish" not in appended
67119
# existing behavior is preserved
68120
assert "disable_print_identity" in appended
121+
mock_remove_flag.assert_not_called()

0 commit comments

Comments
 (0)