Skip to content

Commit

Permalink
Merge pull request #5 from melexis/jql
Browse files Browse the repository at this point in the history
Escape special characters in string for JQL query
  • Loading branch information
Letme authored Apr 7, 2021
2 parents 22aaa54 + 900d4e8 commit fbb4a75
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 11 deletions.
23 changes: 21 additions & 2 deletions mlx/jira_interaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,10 @@ def create_unique_issues(item_ids, jira, general_fields, settings, traceability_
traceability_collection)

jira_field_id = settings['jira_field_id']
matches = jira.search_issues("project={} and {} ~ {!r}".format(project_id_or_key,
jira_field_query_value = escape_special_characters(jira_field)
matches = jira.search_issues("project={} and {} ~ '{}'".format(project_id_or_key,
jira_field_id,
jira_field))
jira_field_query_value))
if matches:
if settings.get('warn_if_exists', False):
LOGGER.warning("Won't create a {} for item {!r} because the Jira API query to check to prevent "
Expand Down Expand Up @@ -191,3 +192,21 @@ def get_info_from_relationship(item, config_for_parent, traceability_collection)
if attr_value:
attendees = attr_value.split(',')
return attendees, jira_field


def escape_special_characters(input_string):
""" Escape special characters to avoid unwanted behavior.
Note that they are not stored in the index so you cannot search for them.
Args:
input_string (str): String to escape special characters of
Returns:
str: Input string that has its special characters escaped
"""
prepared_string = input_string
for special_char in ("\\", "+", "-", "&", "|", "!", "(", ")", "{", "}", "[", "]", "^", "~", "*", "?", ":"):
if special_char in prepared_string:
prepared_string = prepared_string.replace(special_char, "\\" + special_char)
return prepared_string
19 changes: 10 additions & 9 deletions tests/test_jira_interaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def setUp(self):
self.coll = TraceableCollection()
parent = TraceableItem('MEETING-12345_2')
action1 = TraceableItem('ACTION-12345_ACTION_1')
action1.caption = 'Caption for action 1'
action1.caption = 'Caption for action 1?'
action1.set_content('Description for action 1')
action2 = TraceableItem('ACTION-12345_ACTION_2')
action2.caption = 'Caption for action 2'
Expand Down Expand Up @@ -131,7 +131,7 @@ def test_create_jira_issues_unique(self, jira):
basic_auth=('my_username', 'my_password')))
self.assertEqual(jira_mock.search_issues.call_args_list,
[
mock.call("project=MLX12345 and summary ~ 'MEETING-12345_2: Caption for action 1'"),
mock.call("project=MLX12345 and summary ~ 'MEETING\\-12345_2\\: Caption for action 1\\?'"),
mock.call("project=MLX12345 and summary ~ 'Caption for action 2'"),
])

Expand All @@ -140,7 +140,7 @@ def test_create_jira_issues_unique(self, jira):
jira_mock.create_issue.call_args_list,
[
mock.call(
summary='MEETING-12345_2: Caption for action 1',
summary='MEETING-12345_2: Caption for action 1?',
description='Description for action 1',
assignee={'name': 'ABC'},
**self.general_fields
Expand Down Expand Up @@ -187,7 +187,7 @@ def test_notify_watchers(self, jira):
[
mock.call(
description='Description for action 1',
summary='MEETING-12345_2: Caption for action 1',
summary='MEETING-12345_2: Caption for action 1?',
**self.general_fields
),
mock.call(
Expand Down Expand Up @@ -267,7 +267,7 @@ def test_default_project(self, jira):
jira_mock.create_issue.call_args_list,
[
mock.call(
summary='MEETING-12345_2: Caption for action 1',
summary='MEETING-12345_2: Caption for action 1?',
description='Description for action 1',
assignee={'name': 'ABC'},
**self.general_fields
Expand Down Expand Up @@ -322,15 +322,16 @@ def test_tuple_for_relationship_to_parent(self, jira):

self.assertEqual(jira_mock.search_issues.call_args_list,
[
mock.call("project=MLX12345 and summary ~ 'ZZZ-TO_BE_PRIORITIZED: Caption for action 1'"),
mock.call("project=MLX12345 and summary ~ "
"'ZZZ\\-TO_BE_PRIORITIZED\\: Caption for action 1\\?'"),
mock.call("project=MLX12345 and summary ~ 'Caption for action 2'"),
])

self.assertEqual(
jira_mock.create_issue.call_args_list,
[
mock.call(
summary='ZZZ-TO_BE_PRIORITIZED: Caption for action 1',
summary='ZZZ-TO_BE_PRIORITIZED: Caption for action 1?',
description='Description for action 1',
assignee={'name': 'ABC'},
**self.general_fields
Expand All @@ -354,7 +355,7 @@ def test_get_info_from_relationship_tuple(self, _):
attendees, jira_field = dut.get_info_from_relationship(action1, relationship_to_parent, self.coll)

self.assertEqual(attendees, [])
self.assertEqual(jira_field, 'ZZZ-TO_BE_PRIORITIZED: Caption for action 1')
self.assertEqual(jira_field, 'ZZZ-TO_BE_PRIORITIZED: Caption for action 1?')

def test_get_info_from_relationship_str(self, _):
""" Tests dut.get_info_from_relationship with a config_for_parent parameter as str """
Expand All @@ -367,4 +368,4 @@ def test_get_info_from_relationship_str(self, _):
attendees, jira_field = dut.get_info_from_relationship(action1, relationship_to_parent, self.coll)

self.assertEqual(attendees, ['ABC', ' ZZZ'])
self.assertEqual(jira_field, 'MEETING-12345_2: Caption for action 1')
self.assertEqual(jira_field, 'MEETING-12345_2: Caption for action 1?')
2 changes: 2 additions & 0 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ envlist =
clean,
check,
{py37},
requires =
pip>=20.3.4

[testenv]
basepython =
Expand Down

0 comments on commit fbb4a75

Please sign in to comment.