Skip to content

Commit c9c4c42

Browse files
authored
Merge pull request #64 from csoceanu/feature/add-timeframe-parameter
Add timeframe parameter to list_jira_issues function
2 parents dd15952 + ab7cde2 commit c9c4c42

File tree

2 files changed

+107
-3
lines changed

2 files changed

+107
-3
lines changed

src/tools.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ async def list_jira_issues(
5252
status: Optional[str] = None,
5353
priority: Optional[str] = None,
5454
limit: int = 50,
55-
search_text: Optional[str] = None
55+
search_text: Optional[str] = None,
56+
timeframe: int = 30
5657
) -> Dict[str, Any]:
5758
"""
5859
@@ -63,6 +64,7 @@ async def list_jira_issues(
6364
priority: Filter by priority ID
6465
limit: Maximum number of issues to return (default: 50)
6566
search_text: Search in summary and description fields
67+
timeframe: Filter issues updated/created/resolved within last N days (default: 30)
6668
6769
Returns:
6870
Dictionary containing issues list and metadata
@@ -92,6 +94,15 @@ async def list_jira_issues(
9294
search_condition = f"(LOWER(SUMMARY) LIKE '%{sanitize_sql_value(search_text.lower())}%' OR LOWER(DESCRIPTION) LIKE '%{sanitize_sql_value(search_text.lower())}%')"
9395
sql_conditions.append(search_condition)
9496

97+
# Add timeframe filter - check if any of the dates are within the specified timeframe
98+
if timeframe > 0:
99+
timeframe_condition = f"""(
100+
CREATED >= CURRENT_DATE() - INTERVAL '{timeframe} DAYS'
101+
OR UPDATED >= CURRENT_DATE() - INTERVAL '{timeframe} DAYS'
102+
OR RESOLUTIONDATE >= CURRENT_DATE() - INTERVAL '{timeframe} DAYS'
103+
)"""
104+
sql_conditions.append(timeframe_condition)
105+
95106
where_clause = ""
96107
if sql_conditions:
97108
where_clause = "WHERE " + " AND ".join(sql_conditions)
@@ -171,6 +182,7 @@ async def list_jira_issues(
171182
"status": status,
172183
"priority": priority,
173184
"search_text": search_text,
185+
"timeframe": timeframe,
174186
"limit": limit
175187
}
176188
}

tests/test_tools.py

Lines changed: 94 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,8 @@ async def test_list_jira_issues_with_filters(self, mock_mcp, mock_dependencies):
199199
issue_type='Bug',
200200
status='Open',
201201
priority='High',
202-
search_text='test search'
202+
search_text='test search',
203+
timeframe=14
203204
)
204205

205206
# Verify SQL conditions were built correctly
@@ -210,6 +211,14 @@ async def test_list_jira_issues_with_filters(self, mock_mcp, mock_dependencies):
210211
assert "ISSUESTATUS = 'Open'" in sql_call
211212
assert "PRIORITY = 'High'" in sql_call
212213
assert "LOWER(SUMMARY) LIKE '%test search%'" in sql_call
214+
215+
# Verify timeframe condition is included
216+
assert "CREATED >= CURRENT_DATE() - INTERVAL '14 DAYS'" in sql_call
217+
assert "UPDATED >= CURRENT_DATE() - INTERVAL '14 DAYS'" in sql_call
218+
assert "RESOLUTIONDATE >= CURRENT_DATE() - INTERVAL '14 DAYS'" in sql_call
219+
220+
# Verify filters_applied includes timeframe
221+
assert result['filters_applied']['timeframe'] == 14
213222

214223
@pytest.mark.asyncio
215224
async def test_get_jira_issue_details_not_found(self, mock_mcp, mock_dependencies):
@@ -334,4 +343,87 @@ async def test_exception_handling(self, mock_mcp, mock_dependencies):
334343

335344
result = await list_jira_issues()
336345
assert 'error' in result
337-
assert 'Database error' in result['error']
346+
assert 'Database error' in result['error']
347+
348+
@pytest.mark.asyncio
349+
async def test_list_jira_issues_default_timeframe(self, mock_mcp, mock_dependencies):
350+
"""Test list_jira_issues with default timeframe (30 days)"""
351+
mock_dependencies['query'].return_value = []
352+
353+
register_tools(mock_mcp)
354+
list_jira_issues = mock_mcp._registered_tools[0]
355+
356+
# Call without specifying timeframe (should use default 30)
357+
result = await list_jira_issues(project='TEST')
358+
359+
# Verify SQL conditions include default timeframe
360+
mock_dependencies['query'].assert_called_once()
361+
sql_call = mock_dependencies['query'].call_args[0][0]
362+
assert "CREATED >= CURRENT_DATE() - INTERVAL '30 DAYS'" in sql_call
363+
assert "UPDATED >= CURRENT_DATE() - INTERVAL '30 DAYS'" in sql_call
364+
assert "RESOLUTIONDATE >= CURRENT_DATE() - INTERVAL '30 DAYS'" in sql_call
365+
366+
# Verify filters_applied includes default timeframe
367+
assert result['filters_applied']['timeframe'] == 30
368+
369+
@pytest.mark.asyncio
370+
async def test_list_jira_issues_custom_timeframe(self, mock_mcp, mock_dependencies):
371+
"""Test list_jira_issues with custom timeframe (7 days)"""
372+
mock_dependencies['query'].return_value = []
373+
374+
register_tools(mock_mcp)
375+
list_jira_issues = mock_mcp._registered_tools[0]
376+
377+
# Test with custom timeframe
378+
result = await list_jira_issues(project='KONFLUX', timeframe=7)
379+
380+
# Verify SQL conditions include custom timeframe
381+
mock_dependencies['query'].assert_called_once()
382+
sql_call = mock_dependencies['query'].call_args[0][0]
383+
assert "CREATED >= CURRENT_DATE() - INTERVAL '7 DAYS'" in sql_call
384+
assert "UPDATED >= CURRENT_DATE() - INTERVAL '7 DAYS'" in sql_call
385+
assert "RESOLUTIONDATE >= CURRENT_DATE() - INTERVAL '7 DAYS'" in sql_call
386+
387+
# Verify filters_applied includes custom timeframe
388+
assert result['filters_applied']['timeframe'] == 7
389+
390+
@pytest.mark.asyncio
391+
async def test_list_jira_issues_zero_timeframe(self, mock_mcp, mock_dependencies):
392+
"""Test list_jira_issues with timeframe=0 (disabled)"""
393+
mock_dependencies['query'].return_value = []
394+
395+
register_tools(mock_mcp)
396+
list_jira_issues = mock_mcp._registered_tools[0]
397+
398+
# Test with timeframe=0 (should disable timeframe filtering)
399+
result = await list_jira_issues(project='TEST', timeframe=0)
400+
401+
# Verify SQL conditions do NOT include timeframe
402+
mock_dependencies['query'].assert_called_once()
403+
sql_call = mock_dependencies['query'].call_args[0][0]
404+
assert "INTERVAL" not in sql_call
405+
assert "CURRENT_DATE()" not in sql_call
406+
407+
# Verify filters_applied includes timeframe=0
408+
assert result['filters_applied']['timeframe'] == 0
409+
410+
@pytest.mark.asyncio
411+
async def test_list_jira_issues_large_timeframe(self, mock_mcp, mock_dependencies):
412+
"""Test list_jira_issues with large timeframe (365 days)"""
413+
mock_dependencies['query'].return_value = []
414+
415+
register_tools(mock_mcp)
416+
list_jira_issues = mock_mcp._registered_tools[0]
417+
418+
# Test with large timeframe
419+
result = await list_jira_issues(timeframe=365)
420+
421+
# Verify SQL conditions include large timeframe
422+
mock_dependencies['query'].assert_called_once()
423+
sql_call = mock_dependencies['query'].call_args[0][0]
424+
assert "CREATED >= CURRENT_DATE() - INTERVAL '365 DAYS'" in sql_call
425+
assert "UPDATED >= CURRENT_DATE() - INTERVAL '365 DAYS'" in sql_call
426+
assert "RESOLUTIONDATE >= CURRENT_DATE() - INTERVAL '365 DAYS'" in sql_call
427+
428+
# Verify filters_applied includes large timeframe
429+
assert result['filters_applied']['timeframe'] == 365

0 commit comments

Comments
 (0)