Sherman-Morrison/vfc_ci
2021-05-03 15:47:44 +02:00

200 lines
5.3 KiB
Python
Executable File

#!/usr/bin/env python3
# This is the entry point of the Verificarlo CI command line interface, which is
# based on argparse and this article :
# https://mike.depalatis.net/blog/simplifying-argparse.html
# From here, 3 subcommands can be called :
# - setup : create a vfc_ci branch and workflow on the current Git repo
# - test : run and export test results according to the vfc_tests_config.json
# - serve : launch a Bokeh server to visualize run results
import argparse
##########################################################################
# Parameters validation helpers
def is_port(string):
value = int(string)
if value < 0 or value > 65535:
raise argparse.ArgumentTypeError("Value has to be between 0 and 65535")
return value
def is_directory(string):
import os
isdir = os.path.isdir(string)
if not isdir:
raise argparse.ArgumentTypeError("Directory does not exist")
return string
##########################################################################
# Subcommand decorator
cli = argparse.ArgumentParser(
description="Define, run, automatize, and visualize custom Verificarlo tests."
)
subparsers = cli.add_subparsers(dest="subcommand")
def subcommand(description="", args=[], parent=subparsers):
def decorator(func):
parser = parent.add_parser(func.__name__, description=description)
for arg in args:
parser.add_argument(*arg[0], **arg[1])
parser.set_defaults(func=func)
return decorator
def argument(*name_or_flags, **kwargs):
return ([*name_or_flags], kwargs)
##########################################################################
# "setup" subcommand
@subcommand(
description="Create an automated workflow to execute Verificarlo tests.",
args=[
argument(
"git_host",
help="""
specify where your repository is hosted
""",
choices=["github", "gitlab"]
)
]
)
def setup(args):
import ci.setup
ci.setup.setup(args.git_host)
# "test" subcommand
@subcommand(
description="Execute predefined Verificarlo tests and save their results.",
args=[
argument(
"-g", "--is-git-commit",
help="""
When specified, the last Git commit of the local repository (working
directory) will be fetched and associated with the run.
""",
action="store_true"
),
argument(
"-r", "--export-raw-results",
help="""
Specify if an additional HDF5 file containing the raw results must be
exported.
""",
action="store_true"
),
argument(
"-d", "--dry-run",
help="""
Perform a dry run by not saving the test results.
""",
action="store_true"
)
]
)
def test(args):
import ci.test
ci.test.run(args.is_git_commit, args.export_raw_results, args.dry_run)
# "serve" subcommand
@subcommand(
description="""
Start a server to visualize Verificarlo test results.
""",
args=[
argument(
"-s", "--show",
help="""
Specify if the report must be opened in the browser at server
startup.
""",
action="store_true"
),
argument(
"-gd", "--git-directory",
help="""
Path to a local Git repository. The report will be linked to the
remote URL (GitHub and GitLab are supported).
""",
type=is_directory
),
argument(
"-gu", "--git-url",
help="""
GitHub or GitLab repository URL. The report will be linked to this
URL.
""",
type=str
),
argument(
"-p", "--port",
help="""
The port on which the server will run. Defaults to 8080.
""",
type=is_port,
default=8080
),
argument(
"-a", "--allow-origin",
help="""
The origin (URL) from which the report will be accessible.
Port number must not be specified. Defaults to * (allow everything).
""",
type=str,
default="*"
),
argument(
"-l", "--logo",
help="""
Specify the URL of an image to be displayed in the report header.
""",
type=str
)
]
)
def serve(args):
# git_directory and git_url are supposed to be exclusive
if args.git_directory is not None and args.git_url is not None:
raise argparse.ArgumentTypeError(
"\"-gd\" / \"--git-directory\" and \"-gu\" / \"--git-url\" are "
"mutually exclusive. Please make sure to use at most one of them."
)
import ci.serve
ci.serve.serve(
args.show,
args.git_directory,
args.git_url,
args.port,
args.allow_origin,
args.logo
)
###############################################################################
# Main command group and entry point
if __name__ == "__main__":
args = cli.parse_args()
if args.subcommand is None:
cli.print_help()
else:
args.func(args)