Nicolas Dechesne | 3f22575 | 2020-09-29 13:22:53 +0200 | [diff] [blame] | 1 | #!/usr/bin/env python3 |
| 2 | |
Milosz Wasilewski | 68279b2 | 2018-02-21 12:41:02 +0000 | [diff] [blame] | 3 | import collections |
Milosz Wasilewski | f9e70c0 | 2020-09-25 13:19:44 +0100 | [diff] [blame] | 4 | import datetime |
Milosz Wasilewski | 9c00f73 | 2020-08-04 10:29:35 +0100 | [diff] [blame] | 5 | import logging |
Milosz Wasilewski | f5ccdbd | 2016-10-25 18:49:20 +0100 | [diff] [blame] | 6 | import os |
Milosz Wasilewski | 923ed1b | 2020-08-10 16:15:46 +0100 | [diff] [blame] | 7 | import pdfkit |
Milosz Wasilewski | f5ccdbd | 2016-10-25 18:49:20 +0100 | [diff] [blame] | 8 | import subprocess |
| 9 | import yaml |
| 10 | from argparse import ArgumentParser |
Milosz Wasilewski | b504541 | 2016-12-07 11:27:10 +0000 | [diff] [blame] | 11 | from csv import DictWriter |
Milosz Wasilewski | f5ccdbd | 2016-10-25 18:49:20 +0100 | [diff] [blame] | 12 | from jinja2 import Environment, FileSystemLoader |
| 13 | |
| 14 | |
Milosz Wasilewski | 9c00f73 | 2020-08-04 10:29:35 +0100 | [diff] [blame] | 15 | logger = logging.getLogger() |
| 16 | |
| 17 | |
Milosz Wasilewski | 68279b2 | 2018-02-21 12:41:02 +0000 | [diff] [blame] | 18 | class PrependOrderedDict(collections.OrderedDict): |
| 19 | |
| 20 | def prepend(self, key, value, dict_setitem=dict.__setitem__): |
Milosz Wasilewski | 9c00f73 | 2020-08-04 10:29:35 +0100 | [diff] [blame] | 21 | self[key] = value |
| 22 | self.move_to_end(key, last=False) |
Milosz Wasilewski | 68279b2 | 2018-02-21 12:41:02 +0000 | [diff] [blame] | 23 | |
| 24 | |
Milosz Wasilewski | e6f1632 | 2020-08-04 10:30:05 +0100 | [diff] [blame] | 25 | def render(obj, template="testplan.html", templates_dir=None, name=None): |
Milosz Wasilewski | f5ccdbd | 2016-10-25 18:49:20 +0100 | [diff] [blame] | 26 | if name is None: |
| 27 | name = template |
Milosz Wasilewski | e6f1632 | 2020-08-04 10:30:05 +0100 | [diff] [blame] | 28 | if templates_dir is None: |
| 29 | templates_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "templates") |
Milosz Wasilewski | f761ab9 | 2018-02-13 11:21:18 +0000 | [diff] [blame] | 30 | _env = Environment(loader=FileSystemLoader(templates_dir)) |
Milosz Wasilewski | f5ccdbd | 2016-10-25 18:49:20 +0100 | [diff] [blame] | 31 | _template = _env.get_template(template) |
Milosz Wasilewski | f9e70c0 | 2020-09-25 13:19:44 +0100 | [diff] [blame] | 32 | obj['metadata']['now'] = datetime.date.today().strftime("%B %d, %Y") |
Milosz Wasilewski | f5ccdbd | 2016-10-25 18:49:20 +0100 | [diff] [blame] | 33 | _obj = _template.render(obj=obj) |
| 34 | with open("{}".format(name), "wb") as _file: |
| 35 | _file.write(_obj.encode('utf-8')) |
| 36 | |
Nicolas Dechesne | cd2e0f1 | 2020-09-29 11:20:25 +0200 | [diff] [blame] | 37 | # if the template is a .textile template, let's convert the output file to html |
| 38 | if os.path.splitext(name)[1] == '.textile': |
| 39 | import textile |
| 40 | with open("{}".format(name), "r") as _file: |
| 41 | data = _file.read() |
| 42 | with open("{}{}".format(os.path.splitext(name)[0], ".html"), "w") as _file: |
| 43 | _file.write(textile.textile(data)) |
Milosz Wasilewski | f5ccdbd | 2016-10-25 18:49:20 +0100 | [diff] [blame] | 44 | |
Nicolas Dechesne | d932555 | 2020-09-29 13:20:44 +0200 | [diff] [blame] | 45 | |
Milosz Wasilewski | f5ccdbd | 2016-10-25 18:49:20 +0100 | [diff] [blame] | 46 | # get list of repositories and cache them |
| 47 | def repository_list(testplan): |
| 48 | repositories = set() |
Milosz Wasilewski | d5e1dd9 | 2018-02-12 12:08:44 +0000 | [diff] [blame] | 49 | tp_version = testplan['metadata']['format'] |
| 50 | if tp_version == "Linaro Test Plan v2": |
| 51 | if 'manual' in testplan['tests'].keys() and testplan['tests']['manual'] is not None: |
| 52 | for test in testplan['tests']['manual']: |
| 53 | repositories.add(test['repository']) |
| 54 | |
| 55 | if 'automated' in testplan['tests'].keys() and testplan['tests']['automated'] is not None: |
| 56 | for test in testplan['tests']['automated']: |
| 57 | repositories.add(test['repository']) |
| 58 | if tp_version == "Linaro Test Plan v1": |
| 59 | for req in testplan['requirements']: |
| 60 | if 'tests' in req.keys() and req['tests'] is not None: |
| 61 | if 'manual' in req['tests'].keys() and req['tests']['manual'] is not None: |
| 62 | for test in req['tests']['manual']: |
| 63 | repositories.add(test['repository']) |
| 64 | if 'automated' in req['tests'].keys() and req['tests']['automated'] is not None: |
| 65 | for test in req['tests']['automated']: |
| 66 | repositories.add(test['repository']) |
Milosz Wasilewski | f5ccdbd | 2016-10-25 18:49:20 +0100 | [diff] [blame] | 67 | return repositories |
| 68 | |
| 69 | |
| 70 | def clone_repository(repository_url, base_path, ignore=False): |
| 71 | path_suffix = repository_url.rsplit("/", 1)[1] |
| 72 | if path_suffix.endswith(".git"): |
| 73 | path_suffix = path_suffix[:-4] |
| 74 | |
Milosz Wasilewski | b504541 | 2016-12-07 11:27:10 +0000 | [diff] [blame] | 75 | path = os.path.abspath(os.path.join(base_path, path_suffix)) |
Milosz Wasilewski | f5ccdbd | 2016-10-25 18:49:20 +0100 | [diff] [blame] | 76 | if os.path.exists(path) and ignore: |
| 77 | return(repository_url, path) |
Nicolas Dechesne | 1f3fa5b | 2020-10-02 12:15:19 +0200 | [diff] [blame] | 78 | |
| 79 | # if the user does not use --ignore-clone, let's default to updating our local copy |
| 80 | if os.path.exists(path): |
| 81 | subprocess.call(['git', 'pull', '--ff-only'], cwd=path) |
| 82 | return(repository_url, path) |
| 83 | |
Milosz Wasilewski | f5ccdbd | 2016-10-25 18:49:20 +0100 | [diff] [blame] | 84 | # git clone repository_url |
| 85 | subprocess.call(['git', 'clone', repository_url, path]) |
| 86 | # return tuple (repository_url, system_path) |
| 87 | return (repository_url, path) |
| 88 | |
| 89 | |
Milosz Wasilewski | b504541 | 2016-12-07 11:27:10 +0000 | [diff] [blame] | 90 | def test_exists(test, repositories, args): |
Milosz Wasilewski | f5ccdbd | 2016-10-25 18:49:20 +0100 | [diff] [blame] | 91 | test_file_path = os.path.join( |
| 92 | repositories[test['repository']], |
| 93 | test['path'] |
| 94 | ) |
| 95 | current_dir = os.getcwd() |
Milosz Wasilewski | 9c00f73 | 2020-08-04 10:29:35 +0100 | [diff] [blame] | 96 | logger.debug("Current dir: {}".format(current_dir)) |
Milosz Wasilewski | f5ccdbd | 2016-10-25 18:49:20 +0100 | [diff] [blame] | 97 | os.chdir(repositories[test['repository']]) |
| 98 | if 'revision' in test.keys(): |
| 99 | subprocess.call(['git', 'checkout', test['revision']]) |
Milosz Wasilewski | 9a83b8e | 2020-07-10 11:43:33 +0100 | [diff] [blame] | 100 | elif 'branch' in test.keys(): |
| 101 | subprocess.call(['git', 'checkout', test['branch']]) |
Milosz Wasilewski | f5ccdbd | 2016-10-25 18:49:20 +0100 | [diff] [blame] | 102 | else: |
| 103 | # if no revision is specified, use current HEAD |
| 104 | output = subprocess.check_output(['git', 'rev-parse', 'HEAD']) |
Milosz Wasilewski | f9e70c0 | 2020-09-25 13:19:44 +0100 | [diff] [blame] | 105 | test['revision'] = output.decode('utf-8').strip() |
Milosz Wasilewski | f5ccdbd | 2016-10-25 18:49:20 +0100 | [diff] [blame] | 106 | |
| 107 | if not os.path.exists(test_file_path) or not os.path.isfile(test_file_path): |
| 108 | test['missing'] = True |
| 109 | os.chdir(current_dir) |
| 110 | return not test['missing'] |
| 111 | test['missing'] = False |
| 112 | # open the file and render the test |
Nicolas Dechesne | c13d893 | 2020-10-02 12:17:23 +0200 | [diff] [blame] | 113 | subprocess.call(['git', 'checkout', '-q', 'master']) |
Milosz Wasilewski | 9c00f73 | 2020-08-04 10:29:35 +0100 | [diff] [blame] | 114 | logger.debug("Current dir: {}".format(current_dir)) |
Milosz Wasilewski | f5ccdbd | 2016-10-25 18:49:20 +0100 | [diff] [blame] | 115 | os.chdir(current_dir) |
Milosz Wasilewski | 9c00f73 | 2020-08-04 10:29:35 +0100 | [diff] [blame] | 116 | logger.debug("CWD: {}".format(os.getcwd())) |
Milosz Wasilewski | f5ccdbd | 2016-10-25 18:49:20 +0100 | [diff] [blame] | 117 | test_file = open(test_file_path, "r") |
Ryan Harkin | 646fbff | 2020-07-09 22:11:11 +0100 | [diff] [blame] | 118 | test_yaml = yaml.load(test_file.read(), Loader=yaml.FullLoader) |
Milosz Wasilewski | f5ccdbd | 2016-10-25 18:49:20 +0100 | [diff] [blame] | 119 | params_string = "" |
| 120 | if 'parameters' in test.keys(): |
Milosz Wasilewski | 9c00f73 | 2020-08-04 10:29:35 +0100 | [diff] [blame] | 121 | params_string = "_".join(["{0}-{1}".format(param_name, param_value).replace("/", "").replace(" ", "") for param_name, param_value in test['parameters'].items()]) |
Milosz Wasilewski | f5ccdbd | 2016-10-25 18:49:20 +0100 | [diff] [blame] | 122 | test_yaml['params'].update(test['parameters']) |
Nicolas Dechesne | 0d0f5a4 | 2020-09-29 11:26:49 +0200 | [diff] [blame] | 123 | |
| 124 | # add all default params from YAML test def in the test object |
| 125 | if args.single_output: |
| 126 | if 'params' in test_yaml.keys(): |
| 127 | if 'parameters' not in test: |
| 128 | test['parameters'] = {} |
| 129 | for param_name, param_value in test_yaml['params'].items(): |
| 130 | if param_name not in test['parameters'].keys(): |
| 131 | test['parameters'].update({param_name: param_value}) |
Milosz Wasilewski | 9c00f73 | 2020-08-04 10:29:35 +0100 | [diff] [blame] | 132 | logger.debug("PARAM strings: {}".format(params_string)) |
Milosz Wasilewski | f5ccdbd | 2016-10-25 18:49:20 +0100 | [diff] [blame] | 133 | test_name = "{0}_{1}.html".format(test_yaml['metadata']['name'], params_string) |
Milosz Wasilewski | 807c0ea | 2018-02-13 19:14:01 +0000 | [diff] [blame] | 134 | if not args.single_output: |
| 135 | test['filename'] = test_name |
Milosz Wasilewski | b504541 | 2016-12-07 11:27:10 +0000 | [diff] [blame] | 136 | test_path = os.path.join(os.path.abspath(args.output), test_name) |
Milosz Wasilewski | 807c0ea | 2018-02-13 19:14:01 +0000 | [diff] [blame] | 137 | if args.single_output: |
| 138 | # update test plan object |
| 139 | test.update(test_yaml['run']) |
Milosz Wasilewski | 68279b2 | 2018-02-21 12:41:02 +0000 | [diff] [blame] | 140 | # prepend in reversed order so 'name' is on top |
| 141 | test.prepend("os", test_yaml['metadata']['os']) |
| 142 | test.prepend("scope", test_yaml['metadata']['scope']) |
| 143 | test.prepend("description", test_yaml['metadata']['description']) |
Nicolas Dechesne | 548701d | 2020-10-02 11:42:18 +0200 | [diff] [blame] | 144 | if 'name' not in test: |
| 145 | test.prepend("name", test_yaml['metadata']['name']) |
Milosz Wasilewski | 807c0ea | 2018-02-13 19:14:01 +0000 | [diff] [blame] | 146 | else: |
Milosz Wasilewski | e6f1632 | 2020-08-04 10:30:05 +0100 | [diff] [blame] | 147 | render(test_yaml, templates_dir=args.templates_directory, template=args.test_template_name, name=test_path) |
Milosz Wasilewski | f5ccdbd | 2016-10-25 18:49:20 +0100 | [diff] [blame] | 148 | return not test['missing'] |
| 149 | |
| 150 | |
Milosz Wasilewski | b504541 | 2016-12-07 11:27:10 +0000 | [diff] [blame] | 151 | def add_csv_row(requirement, test, args, manual=False): |
| 152 | fieldnames = [ |
| 153 | "req_name", |
| 154 | "req_owner", |
| 155 | "req_category", |
| 156 | "path", |
| 157 | "repository", |
| 158 | "revision", |
| 159 | "parameters", |
| 160 | "mandatory", |
| 161 | "kind", |
| 162 | ] |
| 163 | csv_file_path = os.path.join(os.path.abspath(args.output), args.csv_name) |
| 164 | has_header = False |
| 165 | if os.path.isfile(csv_file_path): |
| 166 | has_header = True |
| 167 | with open(csv_file_path, "ab+") as csv_file: |
| 168 | csvdict = DictWriter(csv_file, fieldnames=fieldnames) |
| 169 | if not has_header: |
| 170 | csvdict.writeheader() |
| 171 | csvdict.writerow( |
| 172 | { |
| 173 | "req_name": requirement.get('name'), |
| 174 | "req_owner": requirement.get('owner'), |
| 175 | "req_category": requirement.get('category'), |
| 176 | "path": test.get('path'), |
| 177 | "repository": test.get('repository'), |
| 178 | "revision": test.get('revision'), |
| 179 | "parameters": test.get('parameters'), |
| 180 | "mandatory": test.get('mandatory'), |
| 181 | "kind": "manual" if manual else "automated", |
| 182 | } |
| 183 | ) |
| 184 | |
| 185 | |
| 186 | def check_coverage(requirement, repositories, args): |
Milosz Wasilewski | f5ccdbd | 2016-10-25 18:49:20 +0100 | [diff] [blame] | 187 | requirement['covered'] = False |
Milosz Wasilewski | b504541 | 2016-12-07 11:27:10 +0000 | [diff] [blame] | 188 | if 'tests' not in requirement.keys() or requirement['tests'] is None: |
Milosz Wasilewski | f5ccdbd | 2016-10-25 18:49:20 +0100 | [diff] [blame] | 189 | return |
| 190 | if 'manual' in requirement['tests'].keys() and requirement['tests']['manual'] is not None: |
| 191 | for test in requirement['tests']['manual']: |
Milosz Wasilewski | b504541 | 2016-12-07 11:27:10 +0000 | [diff] [blame] | 192 | if test_exists(test, repositories, args): |
Milosz Wasilewski | f5ccdbd | 2016-10-25 18:49:20 +0100 | [diff] [blame] | 193 | requirement['covered'] = True |
Milosz Wasilewski | b504541 | 2016-12-07 11:27:10 +0000 | [diff] [blame] | 194 | if args.csv_name: |
| 195 | add_csv_row(requirement, test, args, True) |
Milosz Wasilewski | f5ccdbd | 2016-10-25 18:49:20 +0100 | [diff] [blame] | 196 | if 'automated' in requirement['tests'].keys() and requirement['tests']['automated'] is not None: |
| 197 | for test in requirement['tests']['automated']: |
Milosz Wasilewski | b504541 | 2016-12-07 11:27:10 +0000 | [diff] [blame] | 198 | if test_exists(test, repositories, args): |
Milosz Wasilewski | f5ccdbd | 2016-10-25 18:49:20 +0100 | [diff] [blame] | 199 | requirement['covered'] = True |
Milosz Wasilewski | b504541 | 2016-12-07 11:27:10 +0000 | [diff] [blame] | 200 | if args.csv_name: |
| 201 | add_csv_row(requirement, test, args) |
Milosz Wasilewski | f5ccdbd | 2016-10-25 18:49:20 +0100 | [diff] [blame] | 202 | |
| 203 | |
Milosz Wasilewski | 68279b2 | 2018-02-21 12:41:02 +0000 | [diff] [blame] | 204 | def dict_representer(dumper, data): |
| 205 | return dumper.represent_dict(data.iteritems()) |
| 206 | |
| 207 | |
| 208 | def dict_constructor(loader, node): |
| 209 | return PrependOrderedDict(loader.construct_pairs(node)) |
| 210 | |
| 211 | |
Milosz Wasilewski | f5ccdbd | 2016-10-25 18:49:20 +0100 | [diff] [blame] | 212 | def main(): |
| 213 | parser = ArgumentParser() |
| 214 | parser.add_argument("-f", |
Milosz Wasilewski | b504541 | 2016-12-07 11:27:10 +0000 | [diff] [blame] | 215 | "--file", |
| 216 | dest="testplan_list", |
| 217 | required=True, |
| 218 | nargs="+", |
| 219 | help="Test plan file to be used") |
Milosz Wasilewski | f5ccdbd | 2016-10-25 18:49:20 +0100 | [diff] [blame] | 220 | parser.add_argument("-r", |
Milosz Wasilewski | b504541 | 2016-12-07 11:27:10 +0000 | [diff] [blame] | 221 | "--repositories", |
| 222 | dest="repository_path", |
| 223 | default="repositories", |
| 224 | help="Test plan file to be used") |
| 225 | parser.add_argument("-o", |
| 226 | "--output", |
| 227 | dest="output", |
| 228 | default="output", |
| 229 | help="Destination directory for generated files") |
Milosz Wasilewski | f5ccdbd | 2016-10-25 18:49:20 +0100 | [diff] [blame] | 230 | parser.add_argument("-i", |
Milosz Wasilewski | b504541 | 2016-12-07 11:27:10 +0000 | [diff] [blame] | 231 | "--ignore-clone", |
| 232 | dest="ignore_clone", |
| 233 | action="store_true", |
| 234 | default=False, |
| 235 | help="Ignore cloning repositories and use previously cloned") |
Milosz Wasilewski | 807c0ea | 2018-02-13 19:14:01 +0000 | [diff] [blame] | 236 | parser.add_argument("-s", |
| 237 | "--single-file-output", |
| 238 | dest="single_output", |
| 239 | action="store_true", |
| 240 | default=False, |
| 241 | help="""Render test plan into single HTML file. This option ignores |
| 242 | any metadata that is available in test cases""") |
Milosz Wasilewski | b504541 | 2016-12-07 11:27:10 +0000 | [diff] [blame] | 243 | parser.add_argument("-c", |
| 244 | "--csv", |
| 245 | dest="csv_name", |
| 246 | required=False, |
| 247 | help="Name of CSV to store overall list of requirements and test. If name is absent, the file will not be generated") |
Milosz Wasilewski | e6f1632 | 2020-08-04 10:30:05 +0100 | [diff] [blame] | 248 | parser.add_argument("--test-template-name", |
| 249 | default="test.html", |
| 250 | help="Name of the template used for rendering individual tests") |
| 251 | parser.add_argument("--testplan-template-name", |
Milosz Wasilewski | e6f1632 | 2020-08-04 10:30:05 +0100 | [diff] [blame] | 252 | help="Name of the template used for rendering testsplans") |
| 253 | parser.add_argument("--templates-directory", |
| 254 | default=None, |
| 255 | help="Directory where the templates are located (absolute path)") |
Milosz Wasilewski | 923ed1b | 2020-08-10 16:15:46 +0100 | [diff] [blame] | 256 | parser.add_argument("--pdf", |
| 257 | default=None, |
| 258 | help="Path to the output pdf file. Only works if output generates HTML") |
Milosz Wasilewski | f5ccdbd | 2016-10-25 18:49:20 +0100 | [diff] [blame] | 259 | |
Milosz Wasilewski | 68279b2 | 2018-02-21 12:41:02 +0000 | [diff] [blame] | 260 | _mapping_tag = yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG |
| 261 | yaml.add_representer(PrependOrderedDict, dict_representer) |
| 262 | yaml.add_constructor(_mapping_tag, dict_constructor) |
| 263 | |
Milosz Wasilewski | f5ccdbd | 2016-10-25 18:49:20 +0100 | [diff] [blame] | 264 | args = parser.parse_args() |
Milosz Wasilewski | b504541 | 2016-12-07 11:27:10 +0000 | [diff] [blame] | 265 | if not os.path.exists(os.path.abspath(args.output)): |
Milosz Wasilewski | 9c00f73 | 2020-08-04 10:29:35 +0100 | [diff] [blame] | 266 | os.makedirs(os.path.abspath(args.output), mode=0o755) |
Milosz Wasilewski | b504541 | 2016-12-07 11:27:10 +0000 | [diff] [blame] | 267 | for testplan in args.testplan_list: |
| 268 | if os.path.exists(testplan) and os.path.isfile(testplan): |
| 269 | testplan_file = open(testplan, "r") |
Ryan Harkin | 646fbff | 2020-07-09 22:11:11 +0100 | [diff] [blame] | 270 | tp_obj = yaml.load(testplan_file.read(), Loader=yaml.FullLoader) |
Milosz Wasilewski | b504541 | 2016-12-07 11:27:10 +0000 | [diff] [blame] | 271 | repo_list = repository_list(tp_obj) |
| 272 | repositories = {} |
| 273 | for repo in repo_list: |
| 274 | repo_url, repo_path = clone_repository(repo, args.repository_path, args.ignore_clone) |
| 275 | repositories.update({repo_url: repo_path}) |
| 276 | # ToDo: check test plan structure |
Milosz Wasilewski | d5e1dd9 | 2018-02-12 12:08:44 +0000 | [diff] [blame] | 277 | |
| 278 | tp_version = tp_obj['metadata']['format'] |
| 279 | if tp_version == "Linaro Test Plan v1": |
Nicolas Dechesne | 8ee692d | 2021-02-02 00:00:00 +0100 | [diff] [blame] | 280 | testplan_template = args.testplan_template_name or "testplan.html" |
Milosz Wasilewski | d5e1dd9 | 2018-02-12 12:08:44 +0000 | [diff] [blame] | 281 | for requirement in tp_obj['requirements']: |
| 282 | check_coverage(requirement, repositories, args) |
| 283 | if tp_version == "Linaro Test Plan v2": |
Nicolas Dechesne | 8ee692d | 2021-02-02 00:00:00 +0100 | [diff] [blame] | 284 | testplan_template = args.testplan_template_name or "testplan_v2.html" |
Milosz Wasilewski | d5e1dd9 | 2018-02-12 12:08:44 +0000 | [diff] [blame] | 285 | if 'manual' in tp_obj['tests'].keys() and tp_obj['tests']['manual'] is not None: |
| 286 | for test in tp_obj['tests']['manual']: |
| 287 | test_exists(test, repositories, args) |
| 288 | if 'automated' in tp_obj['tests'].keys() and tp_obj['tests']['automated'] is not None: |
| 289 | for test in tp_obj['tests']['automated']: |
| 290 | test_exists(test, repositories, args) |
Milosz Wasilewski | f9e70c0 | 2020-09-25 13:19:44 +0100 | [diff] [blame] | 291 | # same filename extension as the template |
Nicolas Dechesne | 8ee692d | 2021-02-02 00:00:00 +0100 | [diff] [blame] | 292 | tp_name = tp_obj['metadata']['name'] + os.path.splitext(testplan_template)[1] |
Milosz Wasilewski | b504541 | 2016-12-07 11:27:10 +0000 | [diff] [blame] | 293 | tp_file_name = os.path.join(os.path.abspath(args.output), tp_name) |
Nicolas Dechesne | 8ee692d | 2021-02-02 00:00:00 +0100 | [diff] [blame] | 294 | render(tp_obj, templates_dir=args.templates_directory, template=testplan_template, name=tp_file_name) |
Milosz Wasilewski | b504541 | 2016-12-07 11:27:10 +0000 | [diff] [blame] | 295 | testplan_file.close() |
Milosz Wasilewski | 923ed1b | 2020-08-10 16:15:46 +0100 | [diff] [blame] | 296 | if args.pdf is not None: |
| 297 | pdfkit.from_file(tp_file_name, args.pdf) |
Milosz Wasilewski | f5ccdbd | 2016-10-25 18:49:20 +0100 | [diff] [blame] | 298 | # go through requiremets and for each test: |
| 299 | # - if file exists render test as separate html file |
| 300 | # - if file is missing, indicate missing test (red) |
| 301 | # render test plan with links to test files |
| 302 | # add option to render as single file (for pdf generation) |
| 303 | |
Milosz Wasilewski | 6015206 | 2020-03-02 18:53:29 +0000 | [diff] [blame] | 304 | |
Milosz Wasilewski | f5ccdbd | 2016-10-25 18:49:20 +0100 | [diff] [blame] | 305 | if __name__ == "__main__": |
| 306 | main() |