Skip to content

Commit

Permalink
Fix UUID in playbook regression. (#2639)
Browse files Browse the repository at this point in the history
* Fix UUID in playbook regression.
Add replace all UUIDs in file.

* Add changelog.

* Update demisto_sdk/commands/download/downloader.py

Iterate only on mutual items.

Co-authored-by: dorschw <81086590+dorschw@users.noreply.github.com>

* Update CHANGELOG.md

Co-authored-by: dorschw <81086590+dorschw@users.noreply.github.com>

* Add doc string to replace_uuids method.

* Add replace uuids unit tests.

* Add unit test to test that playbook regex
is working properly.

* Map UUIDs to name from all
automation and integration.
Explicitly replace UUIDs to name
on all files using the UUID to name map.

* PR changes. Use Path instead of os.path.
Add hints.

* Update demisto_sdk/commands/download/downloader.py

Co-authored-by: dorschw <81086590+dorschw@users.noreply.github.com>

* Update changelog.

* Fix comments in Changelog

Co-authored-by: dorschw <81086590+dorschw@users.noreply.github.com>
  • Loading branch information
thefrieddan1 and dorschw committed Jan 25, 2023
1 parent 4cc1cdd commit 52baa50
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 23 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
## Unreleased
* Fixed an issue in **prepare-content** command where large code lines were broken.
* Fixed an issue where git-*renamed_files* were not retrieved properly.
* Added a UUID to name mapper for **download** it replaces UUIDs with names on all downloaded files.

## 1.9.0
* Fixed an issue where the Slack notifier was using a deprecated argument.
Expand Down
66 changes: 47 additions & 19 deletions demisto_sdk/commands/download/downloader.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
import re
import shutil
import tarfile
from pathlib import Path
from tempfile import mkdtemp
from typing import Dict, List, Union
from typing import Dict, List, Tuple, Union

import demisto_client.demisto_api
from demisto_client.demisto_api.rest import ApiException
Expand Down Expand Up @@ -332,10 +333,26 @@ def map_script(script_string: str, scripts_mapper: dict) -> dict:
scripts_mapper[script_id] = script_yml.get("name")
return scripts_mapper

def handle_file(self, string_to_write, member_name, scripts_id_name):
def replace_uuids(self, string_to_write: str, uuid_dict: dict) -> str:
"""
Replace all occurrences of UUIDs in a string with their corresponding values from a dictionary.
Parameters:
- string_to_write (str): The string to search for UUIDs in.
- uuid_dict (dict): A dictionary mapping UUIDs to content item IDs.
Returns:
- str: The modified string with all UUIDs replaced.
"""
uuids = re.findall(UUID_REGEX, string_to_write)

for uuid in set(uuids).intersection(uuid_dict):
string_to_write = string_to_write.replace(uuid, uuid_dict[uuid])
return string_to_write

if "automation-" in member_name:
scripts_id_name = self.map_script(string_to_write, scripts_id_name)
def handle_file(
self, string_to_write: str, member_name: str, scripts_id_name: dict
):

if not self.list_files and re.search(
INCIDENT_FIELD_FILE_NAME_REGEX, member_name
Expand All @@ -354,7 +371,7 @@ def handle_file(self, string_to_write, member_name, scripts_id_name):
if not self.list_files and re.search(LAYOUT_FILE_NAME__REGEX, member_name):
string_to_write = self.handle_layout(string_to_write, scripts_id_name)

return string_to_write, scripts_id_name
return string_to_write

def fetch_custom_content(self) -> bool:
"""
Expand All @@ -376,32 +393,43 @@ def fetch_custom_content(self) -> bool:
tar = tarfile.open(fileobj=io_bytes, mode="r")

scripts_id_name: dict = {}
strings_to_write: List[Tuple[str, str]] = []
for member in tar.getmembers():
file_name: str = self.update_file_prefix(member.name.strip("/"))
file_path: str = os.path.join(self.custom_content_temp_dir, file_name)

extracted_file = tar.extractfile(member)
# File might empty
if extracted_file:
string_to_write = extracted_file.read().decode("utf-8")
string_to_write, scripts_id_name = self.handle_file(
string_to_write, member.name, scripts_id_name
)

try:
with open(file_path, "w") as file:
file.write(string_to_write)

except Exception as e:
print(f"encountered exception {type(e)}: {e}")
print("trying to write with encoding=utf8")
with open(file_path, "w", encoding="utf8") as file:
file.write(string_to_write)
if (
"automation-" in member.name.lower()
or "integration-" in member.name.lower()
):
scripts_id_name = self.map_script(
string_to_write, scripts_id_name
)
strings_to_write.append((string_to_write, member.name))
else:
raise FileNotFoundError(
f"Could not extract files from tar file: {file_path}"
)

for string_to_write, file_name in strings_to_write:
string_to_write = self.handle_file(
string_to_write=string_to_write,
member_name=file_name,
scripts_id_name=scripts_id_name,
)
string_to_write = self.replace_uuids(string_to_write, scripts_id_name)
file_name = self.update_file_prefix(file_name.strip("/"))
path = Path(self.custom_content_temp_dir, file_name)
try:
path.write_text(string_to_write)

except Exception as e:
print(f"encountered exception {type(e)}: {e}")
print("trying to write with encoding=utf8")
path.write_text(string_to_write, encoding="utf8")
return True

except ApiException as e:
Expand Down
51 changes: 47 additions & 4 deletions demisto_sdk/commands/download/tests/downloader_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -1223,8 +1223,51 @@ def test_handle_file(
original_string, object_name, scripts_mapper, expected_string, expected_mapper
):
downloader = Downloader(output="", input="", regex="", all_custom_content=True)
final_string, final_mapper = downloader.handle_file(
original_string, object_name, scripts_mapper
)
final_string = downloader.handle_file(original_string, object_name, scripts_mapper)
assert final_string == expected_string


def test_download_playbook_yaml_is_called():
"""
Test that the `download_playbook_yaml` method is called when `handle_file` is called,
if member name contains the word playbook.
"""
downloader = Downloader(output="", input="", regex="", all_custom_content=True)
with patch.object(downloader, "download_playbook_yaml") as mock:
downloader.handle_file(
"name: TestingPlaybook\ncommonfields:\n id: f1e4c6e5-0d44-48a0-8020-a9711243e918",
"playbook-Testing.yml",
{},
)

mock.assert_called()


@pytest.mark.parametrize(
"original_string, uuids_to_name_map, expected_string",
[
(
"name: TestingScript\ncommonfields:\n id: f1e4c6e5-0d44-48a0-8020-a9711243e918",
{},
"name: TestingScript\ncommonfields:\n id: f1e4c6e5-0d44-48a0-8020-a9711243e918",
),
(
'{"name":"TestingField","script":"f1e4c6e5-0d44-48a0-8020-a9711243e918"}',
{"f1e4c6e5-0d44-48a0-8020-a9711243e918": "TestingScript"},
'{"name":"TestingField","script":"TestingScript"}',
),
(
'{"name":"TestingLayout","detailsV2":{"tabs":[{"sections":[{'
'"items":[{"scriptId":"f1e4c6e5-0d44-48a0-8020-a9711243e918"'
"}]}]}]}}",
{"f1e4c6e5-0d44-48a0-8020-a9711243e918": "TestingScript"},
'{"name":"TestingLayout","detailsV2":{"tabs":[{"sections":[{'
'"items":[{"scriptId":"TestingScript"'
"}]}]}]}}",
),
],
)
def test_replace_uuids(original_string, uuids_to_name_map, expected_string):
downloader = Downloader(output="", input="", regex="", all_custom_content=True)
final_string = downloader.replace_uuids(original_string, uuids_to_name_map)
assert final_string == expected_string
assert final_mapper == expected_mapper

0 comments on commit 52baa50

Please sign in to comment.