Skip to content

Commit b0b7481

Browse files
vkondulalukas-bednar
authored andcommitted
Add strategy to resolve not found issues (#44)
User can specify in cmd or config file what to do if issue ID is not found. It's also possible to disable search for issue ID in doc string and to change pattern for matching issue ID. Issue: #25
1 parent ebb47fd commit b0b7481

File tree

3 files changed

+262
-41
lines changed

3 files changed

+262
-41
lines changed

README.rst

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,23 @@ You can specify jira issue ID in docstring or in pytest.mark.jira decorator.
3737
If you use decorator you can specify optional parameter ``run``. If it's false
3838
and issue is unresolved, the test will be skipped.
3939

40+
You can disable searching for issue ID in doc string by using
41+
``--jira-disable-docs-search`` parameter or by ``docs_search=False``
42+
in `jira.cfg`. It's also possible to change behavior if issue ID was not found
43+
by setting ``--jira-marker-strategy=STRATEGY`` or in config file
44+
as `marker_strategy=STRATEGY`.
45+
46+
You can use one of following strategies:
47+
48+
- open - issue is considered as open (default)
49+
- strict - raise an exception
50+
- ignore - issue id is ignored
51+
- warn - write error message and ignore
52+
53+
By default the regular expression patter for matching jira issue ID is `[A-Z]+-[0-9]+`,
54+
it can by changed by ``--jira-issue-regex=REGEX`` or in a config file by
55+
``jira_regex=REGEX``.
56+
4057
Example
4158
^^^^^^^
4259
.. code:: python
@@ -88,6 +105,9 @@ Usage
88105
# ssl_verification = True/False
89106
# version = foo-1.0
90107
# components = com1,second component,com3
108+
# strategy = [open|strict|warn|ignore] (dealing with not found issues)
109+
# docs_search = False (disable searching for issue id in docs)
110+
# issue_regex = REGEX (replace default `[A-Z]+-[0-9]+` regular expression)
91111

92112
Options can be overridden with command line options. The configuration
93113
file can also be placed in ``/etc/jira.cfg`` and ``~/jira.cfg``.

pytest_jira.py

Lines changed: 101 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -12,54 +12,26 @@
1212
import re
1313
import six
1414
import pytest
15+
import sys
1516
from jira.client import JIRA
1617

1718

1819
class JiraHooks(object):
19-
issue_re = r"([A-Z]+-[0-9]+)"
20-
2120
def __init__(
2221
self,
2322
connection,
23+
marker,
2424
version=None,
2525
components=None,
2626
):
2727
self.conn = connection
28+
self.mark = marker
2829
self.components = set(components) if components else None
2930
self.version = version
3031

3132
# Speed up JIRA lookups for duplicate issues
3233
self.issue_cache = dict()
3334

34-
def get_jira_issues(self, item):
35-
issue_pattern = re.compile(self.issue_re)
36-
jira_ids = []
37-
# Was the jira marker used?
38-
if 'jira' in item.keywords:
39-
marker = item.keywords['jira']
40-
if len(marker.args) == 0:
41-
raise TypeError('JIRA marker requires one, or more, arguments')
42-
jira_ids.extend(item.keywords['jira'].args)
43-
44-
# Was a jira issue referenced in the docstr?
45-
if item.function.__doc__:
46-
jira_ids.extend(
47-
[
48-
m.group(0)
49-
for m in issue_pattern.finditer(item.function.__doc__)
50-
]
51-
)
52-
53-
# Filter valid issues, and return unique issues
54-
for jid in set(jira_ids):
55-
if not issue_pattern.match(jid):
56-
raise ValueError(
57-
'JIRA marker argument `%s` does not match pattern' % jid
58-
)
59-
return list(
60-
set(jira_ids)
61-
)
62-
6335
def is_issue_resolved(self, issue_id):
6436
'''
6537
Returns whether the provided issue ID is resolved (True|False). Will
@@ -70,9 +42,12 @@ def is_issue_resolved(self, issue_id):
7042
try:
7143
self.issue_cache[issue_id] = self.conn.get_issue(issue_id)
7244
except Exception:
73-
self.issue_cache[issue_id] = {'status': 'open'}
45+
self.issue_cache[issue_id] = self.mark.get_default(issue_id)
7446

7547
# Skip test if issue remains unresolved
48+
if self.issue_cache[issue_id] is None:
49+
return True
50+
7651
if self.issue_cache[issue_id]['status'] in ['closed', 'resolved']:
7752
return self.fixed_in_version(issue_id)
7853
else:
@@ -86,7 +61,7 @@ def pytest_runtest_makereport(self, item, call, __multicall__):
8661

8762
rep = __multicall__.execute()
8863
try:
89-
jira_ids = self.get_jira_issues(item)
64+
jira_ids = self.mark.get_jira_issues(item)
9065
except Exception:
9166
jira_ids = []
9267

@@ -112,7 +87,7 @@ def pytest_runtest_setup(self, item):
11287
jira_run = True
11388
if 'jira' in item.keywords:
11489
jira_run = item.keywords['jira'].kwargs.get('run', jira_run)
115-
jira_ids = self.get_jira_issues(item)
90+
jira_ids = self.mark.get_jira_issues(item)
11691

11792
# Check all linked issues
11893
for issue_id in jira_ids:
@@ -201,12 +176,68 @@ def get_url(self):
201176
return self.url
202177

203178

179+
class JiraMarkerReporter(object):
180+
issue_re = r"([A-Z]+-[0-9]+)"
181+
182+
def __init__(self, strategy, docs, patern):
183+
self.issue_pattern = re.compile(patern or self.issue_re)
184+
self.docs = docs
185+
self.strategy = strategy.lower()
186+
187+
def get_jira_issues(self, item):
188+
jira_ids = []
189+
# Was the jira marker used?
190+
if 'jira' in item.keywords:
191+
marker = item.keywords['jira']
192+
if len(marker.args) == 0:
193+
raise TypeError('JIRA marker requires one, or more, arguments')
194+
jira_ids.extend(item.keywords['jira'].args)
195+
196+
# Was a jira issue referenced in the docstr?
197+
if self.docs and item.function.__doc__:
198+
jira_ids.extend(
199+
[
200+
m.group(0)
201+
for m in self.issue_pattern.finditer(item.function.__doc__)
202+
]
203+
)
204+
205+
# Filter valid issues, and return unique issues
206+
for jid in set(jira_ids):
207+
if not self.issue_pattern.match(jid):
208+
raise ValueError(
209+
'JIRA marker argument `%s` does not match pattern' % jid
210+
)
211+
return list(
212+
set(jira_ids)
213+
)
214+
215+
def get_default(self, jid):
216+
if self.strategy == 'open':
217+
return {'status': 'open'}
218+
if self.strategy == 'strict':
219+
raise ValueError(
220+
'JIRA marker argument `%s` was not found' % jid
221+
)
222+
if self.strategy == 'warn':
223+
sys.stderr.write(
224+
'JIRA marker argument `%s` was not found' % jid
225+
)
226+
return None
227+
228+
204229
def _get_value(config, section, name, default=None):
205230
if config.has_option(section, name):
206231
return config.get(section, name)
207232
return default
208233

209234

235+
def _get_bool(config, section, name, default=False):
236+
if config.has_option(section, name):
237+
return config.getboolean(section, name)
238+
return default
239+
240+
210241
def pytest_addoption(parser):
211242
"""
212243
Add a options section to py.test --help for jira integration.
@@ -232,11 +263,6 @@ def pytest_addoption(parser):
232263
]
233264
)
234265

235-
try:
236-
verify = config.getboolean('DEFAULT', 'ssl_verification')
237-
except six.moves.configparser.NoOptionError:
238-
verify = True
239-
240266
group.addoption('--jira-url',
241267
action='store',
242268
dest='jira_url',
@@ -258,8 +284,10 @@ def pytest_addoption(parser):
258284
group.addoption('--jira-no-ssl-verify',
259285
action='store_false',
260286
dest='jira_verify',
261-
default=verify,
262-
help='Disable SSL verification to Jira'
287+
default=_get_bool(
288+
config, 'DEFAULT', 'ssl_verification', True,
289+
),
290+
help='Disable SSL verification to Jira',
263291
)
264292
group.addoption('--jira-components',
265293
action='store',
@@ -274,6 +302,32 @@ def pytest_addoption(parser):
274302
default=_get_value(config, 'DEFAULT', 'version'),
275303
help='Used version'
276304
)
305+
group.addoption('--jira-marker-strategy',
306+
action='store',
307+
dest='jira_marker_strategy',
308+
default=_get_value(
309+
config, 'DEFAULT', 'marker_strategy', 'open'
310+
),
311+
choices=['open', 'strict', 'ignore', 'warn'],
312+
help='''Action if issue ID was not found
313+
open - issue is considered as open (default)
314+
strict - raise an exception
315+
ignore - issue id is ignored
316+
warn - write error message and ignore
317+
''',
318+
)
319+
group.addoption('--jira-disable-docs-search',
320+
action='store_false',
321+
dest='jira_docs',
322+
default=_get_bool(config, 'DEFAULT', 'docs_search', True),
323+
help='Issue ID in doc strings will be ignored'
324+
)
325+
group.addoption('--jira-issue-regex',
326+
action='store',
327+
dest='jira_regex',
328+
default=_get_value(config, 'DEFAULT', 'issue_regex'),
329+
help='Replace default `[A-Z]+-[0-9]+` regular expression'
330+
)
277331

278332

279333
def pytest_configure(config):
@@ -302,10 +356,16 @@ def pytest_configure(config):
302356
config.getvalue('jira_password'),
303357
config.getvalue('jira_verify'),
304358
)
359+
jira_marker = JiraMarkerReporter(
360+
config.getvalue('jira_marker_strategy'),
361+
config.getvalue('jira_docs'),
362+
config.getvalue('jira_regex'),
363+
)
305364
if jira_connection.is_connected():
306365
# if connection to jira fails, plugin won't be loaded
307366
jira_plugin = JiraHooks(
308367
jira_connection,
368+
jira_marker,
309369
config.getvalue('jira_product_version'),
310370
components,
311371
)

0 commit comments

Comments
 (0)