Skip to content

Commit

Permalink
Adjust support for modifying plan templates
Browse files Browse the repository at this point in the history
Add support for modifying all supported steps.
Mention the new functionality in the examples.
Include a simple test for the feature as well.
  • Loading branch information
psss committed Apr 29, 2020
1 parent ecc61d9 commit b0ebba5
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 32 deletions.
8 changes: 8 additions & 0 deletions docs/examples.rst
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,14 @@ Use ``tmt plan create`` to create a new plan with templates::
tmt plans create --template mini /plans/smoke
tmt plans create --t full /plans/features

In order to override default template content directly from the
command line use individual step options and provide desired data
in the ``yaml`` format::

tmt plan create /plans/custom --template mini \
--discover '{how: "fmf", name: "internal", url: "https://internal/repo"}' \
--discover '{how: "fmf", name: "external", url: "https://external/repo"}'

Options ``-f`` or ``--force`` can be used to overwrite existing
files.

Expand Down
2 changes: 2 additions & 0 deletions tests/plan/create/main.fmf
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
summary: Create a test plan using template and command line data
test: ./test.sh
37 changes: 37 additions & 0 deletions tests/plan/create/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
. /usr/share/beakerlib/beakerlib.sh || exit 1

rlJournalStart
rlPhaseStartSetup
rlRun "TMP=\$(mktemp -d)" 0 "Creating tmp directory"
rlRun "pushd $TMP"
rlRun "set -o pipefail"
rlRun "tmt init"
rlPhaseEnd

rlPhaseStartTest "Valid data"
yaml1='{how: "fmf", name: "int", url: "https://int/repo"}'
yaml2='{how: "fmf", name: "ext", url: "https://ext/repo"}'
rlRun "tmt plan create /plans/custom --template mini \
--discover '$yaml1' --discover '$yaml2'"
rlAssertGrep "name: ext" "plans/custom.fmf"
rlAssertGrep "url:.*ext/repo" "plans/custom.fmf"
rlPhaseEnd

rlPhaseStartTest "Invalid yaml"
yaml='{how: "fmf"; name: "int"; url: "https://int/repo"}'
rlRun "tmt plan create /plans/bad --template mini \
--discover '$yaml' 2>&1 | tee output " 1
rlAssertGrep "Invalid yaml data" "output"
rlPhaseEnd

rlPhaseStartTest "Invalid step"
rlRun "tmt plan create /plans/bad --template mini \
--discover '' 2>&1 | tee output " 1
rlAssertGrep "Invalid step data" "output"
rlPhaseEnd

rlPhaseStartCleanup
rlRun "popd"
rlRun "rm -r $TMP" 0 "Removing tmp directory"
rlPhaseEnd
rlJournalEnd
52 changes: 28 additions & 24 deletions tmt/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import os
import re
import fmf
import yaml
import pprint
import random
import string
Expand Down Expand Up @@ -352,33 +353,36 @@ def environment(self):
return self._environment

@staticmethod
def edit_template(content, new_args):
def edit_template(content):
""" Edit the default template with custom values """
args = ['name', 'how', 'url', 'ref', 'path', 'test', 'filter']
new = ''

for data in new_args:
line = tmt.utils.yaml_to_dict(data)
if type(line) is not dict:
raise tmt.utils.GeneralError(
"Invalid YAML provided to --discover option")
content = tmt.utils.yaml_to_dict(content)

#'how' is the only value that needs to be there all the time
if 'how' not in line:
line['how'] = 'fmf'

for key, value in line.items():
if key not in args:
# For each step check for possible command line data
for step in tmt.steps.STEPS:
options = Plan._opt(step)
if not options:
continue
step_data = []

# For each option check for valid yaml and store
for option in options:
try:
data = tmt.utils.yaml_to_dict(option)
if not data:
raise tmt.utils.GeneralError(
f"Invalid step data for {step}: '{data}'.")
step_data.append(data)
except yaml.parser.ParserError as error:
raise tmt.utils.GeneralError(
"Invalid discover option provided, allowed values are ({})".format(args))
f"Invalid yaml data for {step}:\n{error}")

new += ' {}: {}\n'.format(key, value)
# Use list only when multiple step data provided
if len(step_data) == 1:
step_data = step_data[0]
content[step] = step_data

new = re.sub(' name:', ' - name:', new, flags=re.MULTILINE)
content = re.sub(r'discover:.*prepare:', r'discover:\n{}prepare:'.format(new), content,
flags=re.DOTALL)

return content
return tmt.utils.dict_to_yaml(content)

@staticmethod
def overview(tree):
Expand All @@ -393,7 +397,7 @@ def overview(tree):
), fg='blue'))

@staticmethod
def create(name, template, tree, discover, force=False):
def create(name, template, tree, force=False):
""" Create a new plan """
# Prepare paths
(directory, plan) = os.path.split(name)
Expand All @@ -408,8 +412,8 @@ def create(name, template, tree, discover, force=False):
raise tmt.utils.GeneralError(
"Invalid template '{}'.".format(template))

if discover:
content = tmt.Plan.edit_template(content, discover)
# Override template with data provided on command line
content = Plan.edit_template(content)

tmt.utils.create_file(
path=plan_path, content=content,
Expand Down
27 changes: 19 additions & 8 deletions tmt/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -521,18 +521,29 @@ def lint(context, **kwargs):
help='Plan template ({}).'.format(_plan_templates),
prompt='Template ({})'.format(_plan_templates))
@click.option(
'--discover', metavar='\'{YAML}\'',
help='Parameters for discover phase in a yaml format.',
multiple=True)
'--discover', metavar='YAML', multiple=True,
help='Discover phase content in yaml format.')
@click.option(
'--provision', metavar='YAML', multiple=True,
help='Provision phase content in yaml format.')
@click.option(
'--prepare', metavar='YAML', multiple=True,
help='Prepare phase content in yaml format.')
@click.option(
'--execute', metavar='YAML', multiple=True,
help='Execute phase content in yaml format.')
@click.option(
'--report', metavar='YAML', multiple=True,
help='Report phase content in yaml format.')
@click.option(
'--finish', metavar='YAML', multiple=True,
help='Finish phase content in yaml format.')
@verbose_debug_quiet
@force_dry
def create(context, name, template, discover, force, **kwargs):
def create(context, name, template, force, **kwargs):
""" Create a new plan based on given template. """
if context.args:
tmt.Plan.validate_args(context.args)

tmt.Plan._save_context(context)
tmt.Plan.create(name, template, discover, context.obj.tree, force)
tmt.Plan.create(name, template, context.obj.tree, force)

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Story
Expand Down

0 comments on commit b0ebba5

Please sign in to comment.