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

Allow creation of nitrate cases when exporting #185

Merged
merged 2 commits into from
Apr 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 3 additions & 2 deletions tmt/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,8 @@ def lint(self):
elif len(self.summary) > 50:
echo(verdict(2, 'summary should not exceed 50 characters'))

def export(self, format_='yaml', keys=None, environment=None):
def export(
self, format_='yaml', keys=None, environment=None, create=False):
"""
Export test data into requested format

Expand Down Expand Up @@ -235,7 +236,7 @@ def export(self, format_='yaml', keys=None, environment=None):

# Export to Nitrate test case management system
elif format_ == 'nitrate':
return tmt.export.export_to_nitrate(self)
tmt.export.export_to_nitrate(self, create)

# Common node export otherwise
else:
Expand Down
7 changes: 5 additions & 2 deletions tmt/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -515,13 +515,16 @@ def import_(context, paths, makefile, nitrate, purpose, disabled, **kwargs):
@click.option(
'--nitrate', is_flag=True,
help='Export test metadata to Nitrate.')
@click.option(
'--create', is_flag=True,
help="Create test cases in nitrate if they don't exist.")
@click.option(
'--format', 'format_', default='yaml', show_default=True, metavar='FORMAT',
help='Output format.')
@click.option(
'-d', '--debug', is_flag=True,
help='Provide as much debugging details as possible.')
def export(context, format_, nitrate, **kwargs):
def export(context, format_, nitrate, create, **kwargs):
"""
Export test data into the desired format

Expand All @@ -531,7 +534,7 @@ def export(context, format_, nitrate, **kwargs):
tmt.Test._save_context(context)
for test in context.obj.tree.tests():
if nitrate:
test.export(format_='nitrate')
test.export(format_='nitrate', create=create)
else:
echo(test.export(format_=format_))

Expand Down
66 changes: 57 additions & 9 deletions tmt/export.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
import yaml
import fmf
import os
import re

from tmt.utils import ConvertError

log = fmf.utils.Logging('tmt').logger

Expand All @@ -19,25 +22,38 @@
""".lstrip()


def export_to_nitrate(test):
""" Export fmf metadata to nitrate test cases """
def import_nitrate():
""" Conditionally import the nitrate module """
# Need to import nitrate only when really needed. Otherwise we get
# traceback when nitrate not installed or config file not available.
# And we want to keep the core tmt package with minimal dependencies.
try:
global nitrate, DEFAULT_PRODUCT
import nitrate
DEFAULT_PRODUCT = nitrate.Product(name='RHEL Tests')
except ImportError:
raise tmt.utils.ConvertError("Install nitrate to export tests there.")
raise ConvertError("Install nitrate to export tests there.")
except nitrate.NitrateError as error:
raise tmt.utils.ConvertError(error)
raise ConvertError(error)


def export_to_nitrate(test, create):
""" Export fmf metadata to nitrate test cases """
import_nitrate()

new_test_created = False
# Check nitrate test case
try:
nitrate_id = test.node.get('extra-nitrate')[3:]
except KeyError:
return 0
nitrate_case = nitrate.TestCase(int(nitrate_id))
echo(style(f"Test case '{nitrate_case.identifier}' found.", fg='blue'))
nitrate_case = nitrate.TestCase(int(nitrate_id))
echo(style(f"Test case '{nitrate_case.identifier}' found.", fg='blue'))
except TypeError:
# Create a new nitrate test case
if create:
nitrate_case = create_nitrate_case(test)
new_test_created = True
else:
raise ConvertError("Nitrate test case id not found.")

# Components
# First remove any components that are already there
Expand Down Expand Up @@ -137,7 +153,17 @@ def export_to_nitrate(test):
echo(style("Test case '{0}' successfully exported to nitrate.".format(
nitrate_case.identifier), fg='magenta'))

return 0
# Write id of newly created nitrate case to its file
if new_test_created:
fmf_file_path = test.node.sources[-1]
try:
with open(fmf_file_path, encoding='utf-8') as fmf_file:
content = yaml.safe_load(fmf_file)
except IOError:
raise ConvertError("Unable to open '{0}'.".format(fmf_file_path))

content['extra-nitrate'] = nitrate_case.identifier
tmt.convert.write(fmf_file_path, content)


def create_fmf_id(test):
Expand Down Expand Up @@ -166,3 +192,25 @@ def run(command):
fmf_id['path'] = os.path.join('/', os.path.relpath(fmf_root, git_root))

return fmf_id


def create_nitrate_case(test):
""" Create new nitrate case """
import_nitrate()

# Get category from Makefile
try:
with open('Makefile', encoding='utf-8') as makefile_file:
makefile = makefile_file.read()
category = re.search(
r'echo\s+"Type:\s*(.*)"', makefile, re.M).group(1)
# Default to 'Sanity' if Makefile or Type not found
except (IOError, AttributeError):
category = 'Sanity'

# Create the new test case
summary = test.node.get('extra-summary', test.summary)
category = nitrate.Category(name=category, product=DEFAULT_PRODUCT)
testcase = nitrate.TestCase(summary=summary, category=category)
echo(style(f"Test case '{testcase.identifier}' created.", fg='blue'))
return testcase