Skip to content

Commit 1dab3ae

Browse files
feat: add a new flag overwrite for build command (#1916)
**Issue number:** Issue #1913 ADDON-83527 ### PR Type **What kind of change does this PR introduce?** * [x] Feature * [ ] Bug Fix * [ ] Refactoring (no functional or API changes) * [x] Documentation Update * [ ] Maintenance (dependency updates, CI, etc.) ## Summary ### Changes Previously, when a user specified a custom build path using the `--o/--output` parameter, the entire `output_path` was cleaned before building the add-on. This could result in unintended loss of existing files in that directory. Therefore, added a new flag`--overwrite` for the build command. Now, we only attempt to clean the `output_path/<ta_name>` directory if the --overwrite flag is provided. If the --overwrite flag is not passed and the `output_path/<ta_name>` directory already exists, the build will fail and prompt the user to either pass the --overwrite flag or choose a different output path. ### User experience User files and directories will no longer be unintentionally deleted when a custom build path is provided using the `--o/--output` parameter. If the `output_path/<ta_name>` directory already exists, users must explicitly pass the `--overwrite` flag to allow it to be overwritten. ## Checklist If an item doesn't apply to your changes, leave it unchecked. ### Review * [x] self-review - I have performed a self-review of this change according to the [development guidelines](https://splunk.github.io/addonfactory-ucc-generator/contributing/#development-guidelines) * [x] Changes are documented. The documentation is understandable, examples work [(more info)](https://splunk.github.io/addonfactory-ucc-generator/contributing/#documentation-guidelines) * [x] PR title and description follows the [contributing principles](https://splunk.github.io/addonfactory-ucc-generator/contributing/#pull-requests) * [ ] meeting - I have scheduled a meeting or recorded a demo to explain these changes (if there is a video, put a link below and in the ticket) ### Tests See [the testing doc](https://splunk.github.io/addonfactory-ucc-generator/contributing/#build-and-test). * [x] Unit - tests have been added/modified to cover the changes * [ ] Smoke - tests have been added/modified to cover the changes * [ ] UI - tests have been added/modified to cover the changes * [x] coverage - I have checked the code coverage of my changes [(see more)](https://splunk.github.io/addonfactory-ucc-generator/contributing/#checking-the-code-coverage) **Demo/meeting:** *Reviewers are encouraged to request meetings or demos if any part of the change is unclear*
1 parent c13db21 commit 1dab3ae

File tree

5 files changed

+79
-13
lines changed

5 files changed

+79
-13
lines changed

docs/commands.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ It takes the following parameters:
3838
Example: `--pip-custom-flag="--no-compile --prefer-binary --ignore-installed --report path/to/report.json --progress-bar on"`
3939

4040
* `--build-custom-ui` - [optional] Additional flag that will trigger build of custom UI repo (execute build script from `./ui` repository).
41+
* `--overwrite` - [optional] overwrites the already existing add-on directory. By default, you can't build an add-on to an already existing directory.
4142

4243
### Verbose mode
4344

splunk_add_on_ucc_framework/commands/build.py

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -248,13 +248,18 @@ def _get_addon_version(addon_version: Optional[str]) -> str:
248248
return addon_version.strip()
249249

250250

251-
def _get_build_output_path(output_directory: Optional[str] = None) -> str:
251+
def _get_build_output_path(
252+
output_directory: Optional[str] = None, overwrite: bool = False
253+
) -> tuple[str, bool]:
252254
if output_directory is None:
253-
return os.path.join(os.getcwd(), "output")
255+
# To preserve the previous behaviour where we used to clean output dir
256+
# when output_directory was set to None
257+
overwrite = True
258+
return os.path.join(os.getcwd(), "output"), overwrite
254259
else:
255260
if not os.path.isabs(output_directory):
256-
return os.path.join(os.getcwd(), output_directory)
257-
return output_directory
261+
return os.path.join(os.getcwd(), output_directory), overwrite
262+
return os.path.join(output_directory), overwrite
258263

259264

260265
def _get_python_version_from_executable(python_binary_name: str) -> str:
@@ -484,6 +489,7 @@ def generate(
484489
pip_legacy_resolver: bool = False,
485490
pip_custom_flag: Optional[str] = None,
486491
build_custom_ui: bool = False,
492+
overwrite: bool = False,
487493
) -> None:
488494
logger.info(f"ucc-gen version {__version__} is used")
489495
logger.info(f"Python binary name to use: {python_binary_name}")
@@ -495,21 +501,27 @@ def generate(
495501
f"Failed to identify Python version for library installation. Error: {e}"
496502
)
497503
sys.exit(1)
498-
499-
output_directory = _get_build_output_path(output_directory)
500-
logger.info(f"Output folder is {output_directory}")
501504
addon_version = _get_addon_version(addon_version)
502505
logger.info(f"Add-on will be built with version '{addon_version}'")
503506
if not os.path.exists(source):
504507
logger.error(
505508
f"Source directory: '{source}' does not exist. Please verify that given source exists."
506509
)
507510
sys.exit(1)
508-
shutil.rmtree(os.path.join(output_directory), ignore_errors=True)
509-
os.makedirs(os.path.join(output_directory))
510-
logger.info(f"Cleaned out directory {output_directory}")
511511
app_manifest = get_app_manifest(source)
512512
ta_name = app_manifest.get_addon_name()
513+
output_directory, overwrite = _get_build_output_path(output_directory, overwrite)
514+
logger.info(f"Output folder is {output_directory}")
515+
if not overwrite and os.path.exists(os.path.join(output_directory, ta_name)):
516+
logger.error(
517+
f"The location {os.path.join(output_directory,ta_name)} is already taken, use `--overwrite` "
518+
"option to overwrite the content of existing directory."
519+
)
520+
sys.exit(1)
521+
if overwrite:
522+
shutil.rmtree(os.path.join(output_directory, ta_name), ignore_errors=True)
523+
os.makedirs(os.path.join(output_directory, ta_name))
524+
logger.info(f"Cleaned out directory {os.path.join(output_directory,ta_name)}")
513525
generated_files = []
514526

515527
gc_path = _get_and_check_global_config_path(source, config_path)

splunk_add_on_ucc_framework/main.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,12 @@ def main(argv: Optional[Sequence[str]] = None) -> int:
147147
default=False,
148148
required=False,
149149
)
150+
build_parser.add_argument(
151+
"--overwrite",
152+
action="store_true",
153+
default=False,
154+
help="overwrite already present output/add-on dir",
155+
)
150156

151157
package_parser = subparsers.add_parser("package", description="Package an add-on")
152158
package_parser.add_argument(
@@ -304,6 +310,7 @@ def main(argv: Optional[Sequence[str]] = None) -> int:
304310
pip_legacy_resolver=args.pip_legacy_resolver,
305311
pip_custom_flag=args.pip_custom_flag,
306312
build_custom_ui=args.build_custom_ui,
313+
overwrite=args.overwrite,
307314
)
308315
if args.command == "package":
309316
package.package(path_to_built_addon=args.path, output_directory=args.output)

tests/unit/commands/test_build.py

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
)
1818

1919
from splunk_add_on_ucc_framework import __version__
20+
from tests.unit.helpers import get_path_to_source_dir
2021

2122
CURRENT_PATH = os.getcwd()
2223

@@ -74,7 +75,7 @@
7475
],
7576
)
7677
def test_get_build_output_path(output_directory, expected_output_directory):
77-
assert expected_output_directory == _get_build_output_path(output_directory)
78+
assert expected_output_directory == _get_build_output_path(output_directory)[0]
7879

7980

8081
@patch("splunk_add_on_ucc_framework.commands.build.subprocess.run")
@@ -222,8 +223,39 @@ def test_ta_name_mismatch(
222223
)
223224

224225

226+
@patch("os.path.exists")
227+
@patch("splunk_add_on_ucc_framework.commands.build.get_app_manifest")
228+
def test_existing_output_dir(mock_get_app_manifest, mock_os_path, caplog):
229+
mock_os_path.return_value = True
230+
231+
mock_app_manifest = MagicMock()
232+
mock_app_manifest.get_addon_name.return_value = "ta_name_1"
233+
mock_get_app_manifest.return_value = mock_app_manifest
234+
235+
with pytest.raises(SystemExit):
236+
generate(
237+
source="source/path",
238+
addon_version="1.0.0",
239+
output_directory="dummy_path",
240+
python_binary_name="python3",
241+
verbose_file_summary_report=False,
242+
pip_version="latest",
243+
pip_legacy_resolver=False,
244+
)
245+
output_dir = os.path.abspath(
246+
os.path.join(get_path_to_source_dir(), os.pardir, "dummy_path", "ta_name_1")
247+
)
248+
expected_msg = (
249+
f"The location {output_dir} is already taken, use `--overwrite` option to overwrite "
250+
"the content of existing directory."
251+
)
252+
assert expected_msg in caplog.text
253+
254+
225255
@patch("splunk_add_on_ucc_framework.commands.build._get_build_output_path")
226-
def test_uncaught_exception(mock_get_build_output_path, caplog):
256+
@patch("os.path.exists")
257+
def test_uncaught_exception(mock_get_build_output_path, mock_os_path, caplog):
258+
mock_os_path.return_value = True
227259
mock_get_build_output_path.side_effect = ValueError("Some exc msg")
228260

229261
expected_msg_1 = "Uncaught exception occurred. Exception details:"

tests/unit/test_main.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
"pip_legacy_resolver": False,
2222
"pip_custom_flag": False,
2323
"build_custom_ui": False,
24+
"overwrite": False,
2425
},
2526
),
2627
(
@@ -36,6 +37,7 @@
3637
"pip_legacy_resolver": False,
3738
"pip_custom_flag": False,
3839
"build_custom_ui": False,
40+
"overwrite": False,
3941
},
4042
),
4143
(
@@ -51,6 +53,7 @@
5153
"pip_legacy_resolver": False,
5254
"pip_custom_flag": False,
5355
"build_custom_ui": False,
56+
"overwrite": False,
5457
},
5558
),
5659
(
@@ -66,10 +69,11 @@
6669
"pip_legacy_resolver": False,
6770
"pip_custom_flag": False,
6871
"build_custom_ui": False,
72+
"overwrite": False,
6973
},
7074
),
7175
(
72-
["-v", "--source", "package", "--ta-version", "2.1.0"],
76+
["-v", "--source", "package", "--ta-version", "2.1.0", "--overwrite"],
7377
{
7478
"source": "package",
7579
"config_path": None,
@@ -81,6 +85,7 @@
8185
"pip_legacy_resolver": False,
8286
"pip_custom_flag": False,
8387
"build_custom_ui": False,
88+
"overwrite": True,
8489
},
8590
),
8691
(
@@ -103,6 +108,7 @@
103108
"pip_legacy_resolver": False,
104109
"pip_custom_flag": False,
105110
"build_custom_ui": False,
111+
"overwrite": False,
106112
},
107113
),
108114
(
@@ -127,6 +133,7 @@
127133
"pip_legacy_resolver": False,
128134
"pip_custom_flag": False,
129135
"build_custom_ui": False,
136+
"overwrite": False,
130137
},
131138
),
132139
(
@@ -153,6 +160,7 @@
153160
"pip_legacy_resolver": False,
154161
"pip_custom_flag": False,
155162
"build_custom_ui": False,
163+
"overwrite": False,
156164
},
157165
),
158166
(
@@ -180,6 +188,7 @@
180188
"pip_legacy_resolver": False,
181189
"pip_custom_flag": False,
182190
"build_custom_ui": False,
191+
"overwrite": False,
183192
},
184193
),
185194
(
@@ -208,6 +217,7 @@
208217
"pip_legacy_resolver": False,
209218
"pip_custom_flag": False,
210219
"build_custom_ui": False,
220+
"overwrite": False,
211221
},
212222
),
213223
(
@@ -238,6 +248,7 @@
238248
"pip_legacy_resolver": False,
239249
"pip_custom_flag": False,
240250
"build_custom_ui": False,
251+
"overwrite": False,
241252
},
242253
),
243254
(
@@ -269,6 +280,7 @@
269280
"pip_legacy_resolver": True,
270281
"pip_custom_flag": False,
271282
"build_custom_ui": False,
283+
"overwrite": False,
272284
},
273285
),
274286
(
@@ -291,6 +303,7 @@
291303
"pip_legacy_resolver": False,
292304
"pip_custom_flag": False,
293305
"build_custom_ui": False,
306+
"overwrite": False,
294307
},
295308
),
296309
(
@@ -315,6 +328,7 @@
315328
"pip_legacy_resolver": False,
316329
"pip_custom_flag": "--progress-bar on",
317330
"build_custom_ui": False,
331+
"overwrite": False,
318332
},
319333
),
320334
],

0 commit comments

Comments
 (0)