Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bug: Add improved support for single arguments in get_list_args function #3589

Merged
merged 24 commits into from
Jun 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
6b136f8
chore: Add support for single-word arguments in get_list_args function
TommyE123 May 27, 2024
2636ea5
Updated changelog
TommyE123 May 27, 2024
ad7a52f
Added tests and better handling in get_list_args
TommyE123 May 29, 2024
df8a776
Linting
TommyE123 May 29, 2024
6968431
Linting
TommyE123 May 29, 2024
a5b14fd
Linting
TommyE123 May 29, 2024
eecb89e
Merge branch 'oxsecurity:main' into Args_Split_Improvement
TommyE123 May 29, 2024
c580488
Added more tests
TommyE123 May 30, 2024
f0524dd
Escape backslashes
TommyE123 May 30, 2024
e3bf14e
Merge branch 'oxsecurity:main' into Args_Split_Improvement
TommyE123 Jun 2, 2024
58f16d1
quick build
TommyE123 Jun 2, 2024
5c3dd2a
Merge branch 'oxsecurity:main' into Args_Split_Improvement
TommyE123 Jun 2, 2024
8191b53
Comment update
TommyE123 Jun 2, 2024
3800ee7
Merge branch 'main' into Args_Split_Improvement
TommyE123 Jun 2, 2024
a5dedde
- Improve support for single argument in `get_list_args` function
TommyE123 Jun 2, 2024
d94c773
Temp change
TommyE123 Jun 2, 2024
59f614a
Merge branch 'main' into Args_Split_Improvement
TommyE123 Jun 9, 2024
6a02437
Merge branch 'main' into Args_Split_Improvement
TommyE123 Jun 12, 2024
ccf5b24
Merge branch 'Args_Split_Improvement' of https://github.com/TommyE123…
TommyE123 Jun 12, 2024
9d257e0
Fix bad merge
TommyE123 Jun 12, 2024
91b3603
Cleanup and Fixes
TommyE123 Jun 12, 2024
9acf78f
Switched to Pattern matching
TommyE123 Jun 12, 2024
36e5280
Ordered Test Numbers
TommyE123 Jun 13, 2024
0958d4a
Merge branch 'main' into Args_Split_Improvement
TommyE123 Jun 13, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ Note: Can be used with `oxsecurity/megalinter@beta` in your GitHub Action mega-l
- [syft](https://github.com/anchore/syft) use `scan` instead of deprecated `packages` arg
- [Powershell](https://github.com/PowerShell/PSScriptAnalyzer#readme) Error table truncation improvements
- [yamllint](https://github.com/adrienverge/yamllint) fix error/warning count to work with different log output formats
- Improve support for single argument in `get_list_args` function

- Doc

Expand Down
27 changes: 21 additions & 6 deletions megalinter/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -222,15 +222,30 @@ def get_list(request_id, config_var, default=None):
return default


# Retrieve a configuration variable as a list of arguments, handling various input formats.
def get_list_args(request_id, config_var, default=None):
# Retrieve the variable from the configuration
var = get(request_id, config_var, None)
if var is not None:
if isinstance(var, list):
return var
if var == "":

match var:
# None return the default value
case None:
return default
# Blank or whitespace-only strings return empty list
case "" | str() if var.strip() == "":
return []
return shlex.split(var)
return default
# Integer or a Decimal return it as a list
case int() | float():
return [str(var)]
# If already a list just return it
case list():
return var
# If string does not contain spaces, return it as a list
case str() if " " not in var.strip():
return [var]
# Otherwise, split the string using shlex and return the result
case _:
return shlex.split(var)


def set_value(request_id, config_var, val):
Expand Down
110 changes: 110 additions & 0 deletions megalinter/tests/test_megalinter/config_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from megalinter.constants import ML_REPO
from megalinter.MegaLinter import Megalinter
from megalinter.utils import REPO_HOME_DEFAULT
from unittest.mock import patch


class config_test(unittest.TestCase):
Expand Down Expand Up @@ -481,3 +482,112 @@ def get_repository(self):

def get_branch(self):
return os.environ.get("GITHUB_BRANCH", "main")

def test_get_list_args(self):
# This is a test to check the functionality of the get_list_args method.
# It mocks the behavior of the get method within this method and asserts the expected output.
scenarios = [
("01", "none_value", None, None),
("02", "single_boolean_true", True, ['True']),
("03", "single_boolean_false", False, ['False']),
("04", "integer_value", 42, ['42']),
("05", "float_value", 3.14, ['3.14']),
("06", "empty_list", [], []),
("07", "empty_string", "", []),
("08", "single_space", ' ', []),
("09", "double_space", ' ', []),
("10", "empty_quoted_string", '""', ['""']),
("11", "non_empty_list", ["item1", "item2"], ['item1', 'item2']),
("12", "single_quoted_string", "'single_quoted_string'", ["'single_quoted_string'"]),
("13", "space_separated_items", 'item1 item2', ['item1', 'item2']),
("14", "multiple_single_quoted_strings", "'string1' 'string2' 'string3'",
['string1', 'string2', 'string3']),
("15", "mixed_single_and_double_quotes", '"double quoted" \'single quoted\'',
['double quoted', 'single quoted']),
("16", "three_space_separated_items", "item1 item2 item3", ['item1', 'item2', 'item3']),
("17", "four_space_separated_items", "item1 item2 item3 item4", ['item1', 'item2', 'item3', 'item4']),
("18", "five_space_separated_items", "item1 item2 item3 item4 item5",
['item1', 'item2', 'item3', 'item4', 'item5']),
("19", "single_quoted_with_spaces", "' single quoted with spaces '", [" single quoted with spaces "]),
("20", " quoted_with_leading_space", '" leading space"', [" leading space"]),
("21", "quoted_with_trailing_space", '"trailing space "', ["trailing space "]),
("22", "quoted_with_leading_and_trailing_spaces", '" leading and trailing spaces "',
[" leading and trailing spaces "]),
("23", "multiple_quoted_strings_with_spaces", '" string1 " "string2 " " string3 "',
[" string1 ", "string2 ", " string3 "]),
("24", "paths_with_nested_folders", "./nested/folder/file.txt", ['./nested/folder/file.txt']),
("25", "paths_with_parent_directory", "../parent/file.txt", ['../parent/file.txt']),
("26", "paths_with_tilde_home", "~/home/user/file.txt", ['~/home/user/file.txt']),
("27", "paths_with_url_files", "http://example.com/file.txt", ['http://example.com/file.txt']),
("28", "multiple_spaces_between_paths", 'path1 path2', ['path1', 'path2']),
("29", "relative_paths", "./relative/path ./another/relative/path",
['./relative/path', './another/relative/path']),
("30", "paths_with_file_extensions", "./file.txt ./folder/file.py", ['./file.txt', './folder/file.py']),
("31", "paths_with_hidden_files", "./folder/.file.sln ./folder/.hidden",
['./folder/.file.sln', './folder/.hidden']),
("32", "absolute_unix_paths", "/root/path /another/root/path", ['/root/path', '/another/root/path']),
("33", "quoted_paths_with_spaces", '"quoted path/with spaces" "another/quoted path"',
['quoted path/with spaces', 'another/quoted path']),
("34", "paths_with_url_and_local_files", "http://example.com/file.txt ./local/file.txt",
['http://example.com/file.txt', './local/file.txt']),
("35", "mixed_quotes_and_spaces", '"quoted item1" item2 \'quoted item3\' item4',
['quoted item1', 'item2', 'quoted item3', 'item4']),
("36", "command_with_options", 'command --option="value with spaces" --flag',
['command', '--option=value with spaces', "--flag"]),
("37", "list_with_spaces_in_elements", ["item 1", "item 2"], ['item 1', 'item 2']),
("38", "list_with_single_element", ["single_item"], ['single_item']),
("39", "list_with_single_element_with_spaces", ["single item"], ['single item']),
("40", "list_with_spaces_and_quotes", ['"item 1"', "'item 2'"], ['"item 1"', "'item 2'"]),
("41", "list_with_single_quoted_element_with_spaces", ['"single item"'], ['"single item"']),
("42", "list_with_single_element_and_spaces", [" single item "], [" single item "]),
("43", "list_with_single_quoted_element_and_spaces", [' "single item" '], [' "single item" ']),
("44", "list_with_comma_separated_items", "item1,item2,item3", ['item1,item2,item3']),
("45", "list_with_comma_and_space_separated_items", "item1, item2, item3", ['item1,', 'item2,', 'item3']),
("46", "list_with_semicolon_separated_items", "item1;item2;item3", ['item1;item2;item3']),
("47", "list_with_semicolon_and_space_separated_items", "item1; item2; item3", ['item1;', 'item2;', 'item3']),
("48", "list_with_multiple_elements", ["item1", "item2", "item3", "item4"], ['item1', 'item2', 'item3', 'item4']),
("49", "list_with_multiple_elements_with_spaces", ["item 1", "item 2", "item 3", "item 4"],
['item 1', 'item 2', 'item 3', 'item 4']),
("50", "list_with_multiple_quoted_elements_with_spaces", ['"item 1"', '"item 2"', '"item 3"', '"item 4"'],
['"item 1"', '"item 2"', '"item 3"', '"item 4"']),
("51", "list_with_multiple_elements_and_spaces", [" item1 ", " item2 ", " item3 ", " item4 "],
[" item1 ", " item2 ", " item3 ", " item4 "]),
("52", "list_with_multiple_quoted_elements_and_spaces", [' "item1" ', ' "item2" ', ' "item3" ', ' "item4" '],
[' "item1" ', ' "item2" ', ' "item3" ', ' "item4" ']),
("53", "list_with_comma_separated_multiple_items", "item1,item2;item3,item4", ['item1,item2;item3,item4']),
("54", "list_with_comma_and_space_separated_multiple_items", "item1, item2, item3, item4",
['item1,', 'item2,', 'item3,', 'item4']),
("55", "list_with_semicolon_separated_multiple_items", "item1;item2,item3;item4",['item1;item2,item3;item4']),
("56", "list_with_semicolon_and_space_separated_multiple_items", "item1; item2; item3; item4",
['item1;', 'item2;', 'item3;', 'item4']),
("57", "single_windows_path", "C:\\path\\to\\file.txt", ['C:\\path\\to\\file.txt']),
("58", "windows_path_with_spaces", '"C:\\path to\\file.txt"', ['C:\\path to\\file.txt']),
("59", "list_of_two_windows_paths", ["C:\\path\\to\\file1.txt", "C:\\path\\to\\file2.txt"],
['C:\\path\\to\\file1.txt', 'C:\\path\\to\\file2.txt']),
("60", "list_of_two_windows_paths_with_spaces", ['"C:\\path to\\file1.txt"', '"C:\\path to\\file2.txt"'],
['"C:\\path to\\file1.txt"', '"C:\\path to\\file2.txt"']),
("61", "network_share", "\\\\server\\share", ["\\\\server\\share"]),
("62", "network_share_with_spaces", "'\\\\server\\share\\path with spaces\\file.txt'", ['\\\\server\\share\\path with spaces\\file.txt']),
("63", "relative_path", ".\\path\\to\\file.txt", [".\\path\\to\\file.txt"]),
("64", "relative_path_with_spaces", '".\\path to\\file.txt"', ['.\\path to\\file.txt']),
("65", "list_of_two_network_shares", ["\\\\server1\\share\\file1.txt", "\\\\server2\\share\\file2.txt"],
["\\\\server1\\share\\file1.txt", "\\\\server2\\share\\file2.txt"]),
("66", "list_of_two_relative_paths", [".\\path1\\file1.txt", ".\\path2\\file2.txt"], [".\\path1\\file1.txt", ".\\path2\\file2.txt"])

# Commented out cases due to shlex.split removing the /
# ("67", "absolute_windows_paths", "C:\\absolute\\path C:\\another\\absolute\\path",
# ['C:\\absolute\\path', 'C:\\another\\absolute\\path']),
# ("68", "paths_with_environment_variables", "$HOME/file.txt $USERPROFILE\\file1.txt",
# ['$HOME/file.txt', '$USERPROFILE\\file1.txt']),
# ("69", "path_with_mixed_separators", "path/to/file path\\to\\another\\file",
# ['path/to/file', 'path\\to\\another\\file']),
# ("70", "complex_paths_and_files", 'file1 "complex path/file2" file3\\with\\backslashes',
# ['file1', 'complex path/file2', 'file3\\with\\backslashes'])
]

for scenario_number, scenario_name, return_value, expected_result in scenarios:
with self.subTest(scenario_number=scenario_number, scenario_name=scenario_name):
with patch.object(config, 'get', return_value=return_value):
result = config.get_list_args('dummy_request_id', scenario_name)
self.assertEqual(result, expected_result,
f"Failed on result scenario {scenario_number}: {scenario_name}")