|
|
3df609b |
diff --git a/module_build_service/manage.py b/module_build_service/manage.py
|
|
|
3df609b |
index 925b5031..1215bdba 100755
|
|
|
3df609b |
--- a/module_build_service/manage.py
|
|
|
3df609b |
+++ b/module_build_service/manage.py
|
|
|
3df609b |
@@ -5,10 +5,9 @@
|
|
|
3df609b |
-from functools import wraps
|
|
|
3df609b |
+import click
|
|
|
3df609b |
import getpass
|
|
|
3df609b |
import logging
|
|
|
3df609b |
import os
|
|
|
3df609b |
import sys
|
|
|
3df609b |
-import textwrap
|
|
|
3df609b |
|
|
|
3df609b |
import flask_migrate
|
|
|
3df609b |
-from flask_script import Manager, prompt_bool
|
|
|
3df609b |
+from flask.cli import FlaskGroup
|
|
|
3df609b |
from werkzeug.datastructures import FileStorage
|
|
|
3df609b |
@@ -21,74 +20,34 @@ from module_build_service.builder.MockModuleBuilder import (
|
|
|
3df609b |
from module_build_service.common.errors import StreamAmbigous, StreamNotXyz
|
|
|
3df609b |
-from module_build_service.common.logger import level_flags
|
|
|
3df609b |
from module_build_service.common.utils import load_mmd_file, import_mmd
|
|
|
3df609b |
import module_build_service.scheduler.consumer
|
|
|
3df609b |
from module_build_service.scheduler.db_session import db_session
|
|
|
3df609b |
import module_build_service.scheduler.local
|
|
|
3df609b |
from module_build_service.web.submit import submit_module_build_from_yaml
|
|
|
3df609b |
|
|
|
3df609b |
-
|
|
|
3df609b |
-def create_app(debug=False, verbose=False, quiet=False):
|
|
|
3df609b |
- # logging (intended for flask-script, see manage.py)
|
|
|
3df609b |
- log = logging.getLogger(__name__)
|
|
|
3df609b |
- if debug:
|
|
|
3df609b |
- log.setLevel(level_flags["debug"])
|
|
|
3df609b |
- elif verbose:
|
|
|
3df609b |
- log.setLevel(level_flags["verbose"])
|
|
|
3df609b |
- elif quiet:
|
|
|
3df609b |
- log.setLevel(level_flags["quiet"])
|
|
|
3df609b |
-
|
|
|
3df609b |
- return app
|
|
|
3df609b |
-
|
|
|
3df609b |
-
|
|
|
3df609b |
-manager = Manager(create_app)
|
|
|
3df609b |
-help_args = ("-?", "--help")
|
|
|
3df609b |
-manager.help_args = help_args
|
|
|
3df609b |
-migrations_dir = os.path.join(os.path.abspath(os.path.dirname(__file__)),
|
|
|
3df609b |
- 'migrations')
|
|
|
3df609b |
+migrations_dir = os.path.join(os.path.abspath(os.path.dirname(__file__)), "migrations")
|
|
|
3df609b |
migrate = flask_migrate.Migrate(app, db, directory=migrations_dir)
|
|
|
3df609b |
-manager.add_command("db", flask_migrate.MigrateCommand)
|
|
|
3df609b |
-manager.add_option("-d", "--debug", dest="debug", action="store_true")
|
|
|
3df609b |
-manager.add_option("-v", "--verbose", dest="verbose", action="store_true")
|
|
|
3df609b |
-manager.add_option("-q", "--quiet", dest="quiet", action="store_true")
|
|
|
3df609b |
|
|
|
3df609b |
|
|
|
3df609b |
-def console_script_help(f):
|
|
|
3df609b |
- @wraps(f)
|
|
|
3df609b |
- def wrapped(*args, **kwargs):
|
|
|
3df609b |
- import sys
|
|
|
3df609b |
+@click.group(cls=FlaskGroup, create_app=lambda *args, **kwargs: app)
|
|
|
3df609b |
+def cli():
|
|
|
3df609b |
+ """MBS manager"""
|
|
|
3df609b |
|
|
|
3df609b |
- if any([arg in help_args for arg in sys.argv[1:]]):
|
|
|
3df609b |
- command = os.path.basename(sys.argv[0])
|
|
|
3df609b |
- print(textwrap.dedent(
|
|
|
3df609b |
- """\
|
|
|
3df609b |
- {0}
|
|
|
3df609b |
-
|
|
|
3df609b |
- Usage: {0} [{1}]
|
|
|
3df609b |
-
|
|
|
3df609b |
- See also:
|
|
|
3df609b |
- mbs-manager(1)
|
|
|
3df609b |
- """).strip().format(command, "|".join(help_args))
|
|
|
3df609b |
- )
|
|
|
3df609b |
- sys.exit(2)
|
|
|
3df609b |
- r = f(*args, **kwargs)
|
|
|
3df609b |
- return r
|
|
|
3df609b |
|
|
|
3df609b |
- return wrapped
|
|
|
3df609b |
-
|
|
|
3df609b |
-
|
|
|
3df609b |
-@console_script_help
|
|
|
3df609b |
-@manager.command
|
|
|
3df609b |
+@cli.command("upgradedb")
|
|
|
3df609b |
def upgradedb():
|
|
|
3df609b |
""" Upgrades the database schema to the latest revision
|
|
|
3df609b |
"""
|
|
|
3df609b |
app.config["SERVER_NAME"] = "localhost"
|
|
|
3df609b |
- # TODO: configurable?
|
|
|
3df609b |
- migrations_dir = os.path.join(os.path.abspath(os.path.dirname(__file__)), "migrations")
|
|
|
3df609b |
with app.app_context():
|
|
|
3df609b |
flask_migrate.upgrade(directory=migrations_dir)
|
|
|
3df609b |
|
|
|
3df609b |
|
|
|
3df609b |
-@manager.command
|
|
|
3df609b |
+def upgradedb_entrypoint():
|
|
|
3df609b |
+ """Entrypoint for command mbs-upgradedb"""
|
|
|
3df609b |
+ upgradedb()
|
|
|
3df609b |
+
|
|
|
3df609b |
+
|
|
|
3df609b |
+@cli.command("cleardb")
|
|
|
3df609b |
def cleardb():
|
|
|
3df609b |
""" Clears the database
|
|
|
3df609b |
"""
|
|
|
3df609b |
@@ -96,8 +53,8 @@ def cleardb():
|
|
|
3df609b |
models.ComponentBuild.query.delete()
|
|
|
3df609b |
|
|
|
3df609b |
|
|
|
3df609b |
-@console_script_help
|
|
|
3df609b |
-@manager.command
|
|
|
3df609b |
+@cli.command("import_module")
|
|
|
3df609b |
+@click.argument("mmd_file", type=click.Path(exists=True))
|
|
|
3df609b |
def import_module(mmd_file):
|
|
|
3df609b |
""" Imports the module from mmd_file
|
|
|
3df609b |
"""
|
|
|
3df609b |
@@ -117,41 +74,56 @@ def import_module(mmd_file):
|
|
|
3df609b |
return collected
|
|
|
3df609b |
|
|
|
3df609b |
|
|
|
3df609b |
-@manager.option("--stream", action="store", dest="stream")
|
|
|
3df609b |
-@manager.option("--file", action="store", dest="yaml_file")
|
|
|
3df609b |
-@manager.option("--srpm", action="append", default=[], dest="srpms", metavar="SRPM")
|
|
|
3df609b |
-@manager.option("--skiptests", action="store_true", dest="skiptests")
|
|
|
3df609b |
-@manager.option("--offline", action="store_true", dest="offline")
|
|
|
3df609b |
-@manager.option(
|
|
|
3df609b |
- '--buildrequires', action='append', metavar='name:stream',
|
|
|
3df609b |
- dest='buildrequires', default=[],
|
|
|
3df609b |
- help='Buildrequires to override in the form of "name:stream"'
|
|
|
3df609b |
-)
|
|
|
3df609b |
-@manager.option(
|
|
|
3df609b |
- '--requires', action='append', metavar='name:stream',
|
|
|
3df609b |
- dest='requires', default=[],
|
|
|
3df609b |
- help='Requires to override in the form of "name:stream"'
|
|
|
3df609b |
-)
|
|
|
3df609b |
-@manager.option("-d", "--debug", action="store_true", dest="log_debug")
|
|
|
3df609b |
-@manager.option("-l", "--add-local-build", action="append", default=None, dest="local_build_nsvs")
|
|
|
3df609b |
-@manager.option("-s", "--set-stream", action="append", default=[], dest="default_streams")
|
|
|
3df609b |
-@manager.option(
|
|
|
3df609b |
- "-r", "--platform-repo-file", action="append", default=[], dest="platform_repofiles"
|
|
|
3df609b |
+@cli.command("build_module_locally")
|
|
|
3df609b |
+@click.option("--stream", metavar="STREAM")
|
|
|
3df609b |
+@click.option(
|
|
|
3df609b |
+ "--file", "yaml_file",
|
|
|
3df609b |
+ metavar="FILE",
|
|
|
3df609b |
+ required=True,
|
|
|
3df609b |
+ type=click.Path(exists=True),
|
|
|
3df609b |
+)
|
|
|
3df609b |
+@click.option("--srpm", "srpms", metavar="SRPM", multiple=True)
|
|
|
3df609b |
+@click.option("--skiptests", is_flag=True)
|
|
|
3df609b |
+@click.option("--offline", is_flag=True)
|
|
|
3df609b |
+@click.option(
|
|
|
3df609b |
+ '--buildrequires', "buildrequires", multiple=True,
|
|
|
3df609b |
+ metavar='name:stream', default=[],
|
|
|
3df609b |
+ help='Buildrequires to override in the form of "name:stream"'
|
|
|
3df609b |
+)
|
|
|
3df609b |
+@click.option(
|
|
|
3df609b |
+ '--requires', "requires", multiple=True,
|
|
|
3df609b |
+ metavar='name:stream', default=[],
|
|
|
3df609b |
+ help='Requires to override in the form of "name:stream"'
|
|
|
3df609b |
+)
|
|
|
3df609b |
+@click.option("-d", "--debug", "log_debug", is_flag=True)
|
|
|
3df609b |
+@click.option(
|
|
|
3df609b |
+ "-l", "--add-local-build", "local_build_nsvs",
|
|
|
3df609b |
+ metavar="NSV", multiple=True
|
|
|
3df609b |
+)
|
|
|
3df609b |
+@click.option(
|
|
|
3df609b |
+ "-s", "--set-stream", "default_streams",
|
|
|
3df609b |
+ metavar="STREAM", multiple=True
|
|
|
3df609b |
)
|
|
|
3df609b |
-@manager.option("-p", "--platform-id", action="store", default=None, dest="platform_id")
|
|
|
3df609b |
+@click.option(
|
|
|
3df609b |
+ "-r", "--platform-repo-file", "platform_repofiles",
|
|
|
3df609b |
+ metavar="FILE",
|
|
|
3df609b |
+ type=click.Path(exists=True),
|
|
|
3df609b |
+ multiple=True
|
|
|
3df609b |
+)
|
|
|
3df609b |
+@click.option("-p", "--platform-id", metavar="PLATFORM_ID")
|
|
|
3df609b |
def build_module_locally(
|
|
|
3df609b |
- local_build_nsvs=None,
|
|
|
3df609b |
+ stream=None,
|
|
|
3df609b |
yaml_file=None,
|
|
|
3df609b |
srpms=None,
|
|
|
3df609b |
- stream=None,
|
|
|
3df609b |
skiptests=False,
|
|
|
3df609b |
- default_streams=None,
|
|
|
3df609b |
offline=False,
|
|
|
3df609b |
+ log_debug=False,
|
|
|
3df609b |
+ local_build_nsvs=None,
|
|
|
3df609b |
+ default_streams=None,
|
|
|
3df609b |
platform_repofiles=None,
|
|
|
3df609b |
platform_id=None,
|
|
|
3df609b |
requires=None,
|
|
|
3df609b |
buildrequires=None,
|
|
|
3df609b |
- log_debug=False,
|
|
|
3df609b |
):
|
|
|
3df609b |
""" Performs local module build using Mock
|
|
|
3df609b |
"""
|
|
|
3df609b |
@@ -233,14 +193,11 @@ def build_module_locally(
|
|
|
3df609b |
sys.exit(1)
|
|
|
3df609b |
|
|
|
3df609b |
|
|
|
3df609b |
-@manager.option(
|
|
|
3df609b |
- "identifier",
|
|
|
3df609b |
- metavar="NAME:STREAM[:VERSION[:CONTEXT]]",
|
|
|
3df609b |
- help="Identifier for selecting module builds to retire",
|
|
|
3df609b |
-)
|
|
|
3df609b |
-@manager.option(
|
|
|
3df609b |
+@cli.command("retire")
|
|
|
3df609b |
+@click.argument("identifier", metavar="NAME:STREAM[:VERSION[:CONTEXT]]")
|
|
|
3df609b |
+@click.option(
|
|
|
3df609b |
"--confirm",
|
|
|
3df609b |
- action="store_true",
|
|
|
3df609b |
+ is_flag=True,
|
|
|
3df609b |
default=False,
|
|
|
3df609b |
help="Perform retire operation without prompting",
|
|
|
3df609b |
)
|
|
|
3df609b |
@@ -273,7 +244,8 @@ def retire(identifier, confirm=False):
|
|
|
3df609b |
logging.info("\t%s", ":".join((build.name, build.stream, build.version, build.context)))
|
|
|
3df609b |
|
|
|
3df609b |
# Prompt for confirmation
|
|
|
3df609b |
- is_confirmed = confirm or prompt_bool("Retire {} module builds?".format(len(module_builds)))
|
|
|
3df609b |
+ confirm_msg = "Retire {} module builds?".format(len(module_builds))
|
|
|
3df609b |
+ is_confirmed = confirm or click.confirm(confirm_msg, abort=False)
|
|
|
3df609b |
if not is_confirmed:
|
|
|
3df609b |
logging.info("Module builds were NOT retired.")
|
|
|
3df609b |
return
|
|
|
3df609b |
@@ -288,8 +260,10 @@ def retire(identifier, confirm=False):
|
|
|
3df609b |
logging.info("Module builds retired.")
|
|
|
3df609b |
|
|
|
3df609b |
|
|
|
3df609b |
-@console_script_help
|
|
|
3df609b |
-@manager.command
|
|
|
3df609b |
+@cli.command("run")
|
|
|
3df609b |
+@click.option("-h", "--host", metavar="HOST", help="Bind to this host.")
|
|
|
3df609b |
+@click.option("-p", "--port", metavar="PORT", help="Bind to this port along with --host.")
|
|
|
3df609b |
+@click.option("-d", "--debug", is_flag=True, default=False, help="Run frontend in debug mode.")
|
|
|
3df609b |
def run(host=None, port=None, debug=None):
|
|
|
3df609b |
""" Runs the Flask app, locally. Intended for dev instances, should not be used for production.
|
|
|
3df609b |
"""
|
|
|
3df609b |
@@ -302,9 +276,5 @@ def run(host=None, port=None, debug=None):
|
|
|
3df609b |
app.run(host=host, port=port, debug=debug)
|
|
|
3df609b |
|
|
|
3df609b |
|
|
|
3df609b |
-def manager_wrapper():
|
|
|
3df609b |
- manager.run()
|
|
|
3df609b |
-
|
|
|
3df609b |
-
|
|
|
3df609b |
if __name__ == "__main__":
|
|
|
3df609b |
- manager_wrapper()
|
|
|
3df609b |
+ cli()
|
|
|
3df609b |
diff --git a/requirements.txt b/requirements.txt
|
|
|
3df609b |
index 9ea96f50..17ea4df0 100644
|
|
|
3df609b |
--- a/requirements.txt
|
|
|
3df609b |
+++ b/requirements.txt
|
|
|
3df609b |
@@ -1,10 +1,10 @@
|
|
|
3df609b |
+click
|
|
|
3df609b |
distro
|
|
|
3df609b |
dogpile.cache
|
|
|
3df609b |
enum34
|
|
|
3df609b |
fedmsg
|
|
|
3df609b |
Flask
|
|
|
3df609b |
Flask-Migrate
|
|
|
3df609b |
-Flask-Script
|
|
|
3df609b |
Flask-SQLAlchemy
|
|
|
3df609b |
funcsigs # Python2 only
|
|
|
3df609b |
futures # Python 2 only
|
|
|
3df609b |
diff --git a/setup.py b/setup.py
|
|
|
3df609b |
index 7eac415c..09cd3b23 100644
|
|
|
3df609b |
--- a/setup.py
|
|
|
3df609b |
+++ b/setup.py
|
|
|
3df609b |
@@ -39,9 +39,9 @@ setup(
|
|
|
3df609b |
dependency_links=deps_links,
|
|
|
3df609b |
entry_points={
|
|
|
3df609b |
"console_scripts": [
|
|
|
3df609b |
- "mbs-upgradedb = module_build_service.manage:upgradedb",
|
|
|
3df609b |
+ "mbs-upgradedb = module_build_service.manage:upgradedb_entrypoint",
|
|
|
3df609b |
"mbs-frontend = module_build_service.manage:run",
|
|
|
3df609b |
- "mbs-manager = module_build_service.manage:manager_wrapper",
|
|
|
3df609b |
+ "mbs-manager = module_build_service.manage:cli",
|
|
|
3df609b |
],
|
|
|
3df609b |
"moksha.consumer": "mbsconsumer = module_build_service.scheduler.consumer:MBSConsumer",
|
|
|
3df609b |
"mbs.messaging_backends": [
|
|
|
3df609b |
diff --git a/tests/test_manage.py b/tests/test_manage.py
|
|
|
3df609b |
index 6d3026c8..44ab8638 100644
|
|
|
3df609b |
--- a/tests/test_manage.py
|
|
|
3df609b |
+++ b/tests/test_manage.py
|
|
|
3df609b |
@@ -5,10 +5,9 @@ from __future__ import absolute_import
|
|
|
3df609b |
from mock import patch
|
|
|
3df609b |
import pytest
|
|
|
3df609b |
|
|
|
3df609b |
-from module_build_service import app
|
|
|
3df609b |
+from module_build_service import app, manage as mbs_manager
|
|
|
3df609b |
from module_build_service.common import models
|
|
|
3df609b |
from module_build_service.common.models import BUILD_STATES, ModuleBuild
|
|
|
3df609b |
-from module_build_service.manage import manager_wrapper, retire
|
|
|
3df609b |
from module_build_service.scheduler.db_session import db_session
|
|
|
3df609b |
from module_build_service.web.utils import deps_to_dict
|
|
|
3df609b |
from tests import clean_database, staged_data_filename
|
|
|
3df609b |
@@ -30,10 +29,12 @@ class TestMBSManage:
|
|
|
3df609b |
)
|
|
|
3df609b |
def test_retire_identifier_validation(self, identifier, is_valid):
|
|
|
3df609b |
if is_valid:
|
|
|
3df609b |
- retire(identifier)
|
|
|
3df609b |
+ with pytest.raises(SystemExit) as exc_info:
|
|
|
3df609b |
+ mbs_manager.cli(["retire", identifier])
|
|
|
3df609b |
+ assert 0 == exc_info
|
|
|
3df609b |
else:
|
|
|
3df609b |
with pytest.raises(ValueError):
|
|
|
3df609b |
- retire(identifier)
|
|
|
3df609b |
+ mbs_manager.cli(["retire", identifier])
|
|
|
3df609b |
|
|
|
3df609b |
@pytest.mark.parametrize(
|
|
|
3df609b |
("overrides", "identifier", "changed_count"),
|
|
|
3df609b |
@@ -47,9 +48,9 @@ class TestMBSManage:
|
|
|
3df609b |
({"context": "pickme"}, "spam:eggs:ham", 2),
|
|
|
3df609b |
),
|
|
|
3df609b |
)
|
|
|
3df609b |
- @patch("module_build_service.manage.prompt_bool")
|
|
|
3df609b |
- def test_retire_build(self, prompt_bool, overrides, identifier, changed_count):
|
|
|
3df609b |
- prompt_bool.return_value = True
|
|
|
3df609b |
+ @patch("click.confirm")
|
|
|
3df609b |
+ def test_retire_build(self, confirm, overrides, identifier, changed_count):
|
|
|
3df609b |
+ confirm.return_value = True
|
|
|
3df609b |
|
|
|
3df609b |
module_builds = (
|
|
|
3df609b |
db_session.query(ModuleBuild)
|
|
|
3df609b |
@@ -71,7 +72,10 @@ class TestMBSManage:
|
|
|
3df609b |
|
|
|
3df609b |
db_session.commit()
|
|
|
3df609b |
|
|
|
3df609b |
- retire(identifier)
|
|
|
3df609b |
+ with pytest.raises(SystemExit) as exc_info:
|
|
|
3df609b |
+ mbs_manager.cli(["retire", identifier])
|
|
|
3df609b |
+ assert 0 == exc_info.value
|
|
|
3df609b |
+
|
|
|
3df609b |
retired_module_builds = (
|
|
|
3df609b |
db_session.query(ModuleBuild)
|
|
|
3df609b |
.filter_by(state=BUILD_STATES["garbage"])
|
|
|
3df609b |
@@ -93,11 +97,11 @@ class TestMBSManage:
|
|
|
3df609b |
(False, True, True)
|
|
|
3df609b |
),
|
|
|
3df609b |
)
|
|
|
3df609b |
- @patch("module_build_service.manage.prompt_bool")
|
|
|
3df609b |
+ @patch("click.confirm")
|
|
|
3df609b |
def test_retire_build_confirm_prompt(
|
|
|
3df609b |
- self, prompt_bool, confirm_prompt, confirm_arg, confirm_expected
|
|
|
3df609b |
+ self, confirm, confirm_prompt, confirm_arg, confirm_expected
|
|
|
3df609b |
):
|
|
|
3df609b |
- prompt_bool.return_value = confirm_prompt
|
|
|
3df609b |
+ confirm.return_value = confirm_prompt
|
|
|
3df609b |
|
|
|
3df609b |
module_builds = db_session.query(ModuleBuild).filter_by(state=BUILD_STATES["ready"]).all()
|
|
|
3df609b |
# Verify our assumption of the amount of ModuleBuilds in database
|
|
|
3df609b |
@@ -106,15 +110,17 @@ class TestMBSManage:
|
|
|
3df609b |
for x, build in enumerate(module_builds):
|
|
|
3df609b |
build.name = "spam" + str(x) if x > 0 else "spam"
|
|
|
3df609b |
build.stream = "eggs"
|
|
|
3df609b |
-
|
|
|
3df609b |
db_session.commit()
|
|
|
3df609b |
|
|
|
3df609b |
- retire("spam:eggs", confirm_arg)
|
|
|
3df609b |
+ cmd = ["retire", "spam:eggs"] + (["--confirm"] if confirm_arg else [])
|
|
|
3df609b |
+ with pytest.raises(SystemExit) as exc_info:
|
|
|
3df609b |
+ mbs_manager.cli(cmd)
|
|
|
3df609b |
+ assert 0 == exc_info.value
|
|
|
3df609b |
+
|
|
|
3df609b |
+ expected_changed_count = 1 if confirm_expected else 0
|
|
|
3df609b |
retired_module_builds = (
|
|
|
3df609b |
db_session.query(ModuleBuild).filter_by(state=BUILD_STATES["garbage"]).all()
|
|
|
3df609b |
)
|
|
|
3df609b |
-
|
|
|
3df609b |
- expected_changed_count = 1 if confirm_expected else 0
|
|
|
3df609b |
assert len(retired_module_builds) == expected_changed_count
|
|
|
3df609b |
|
|
|
3df609b |
|
|
|
3df609b |
@@ -156,7 +162,7 @@ class TestCommandBuildModuleLocally:
|
|
|
3df609b |
original_db_uri = app.config["SQLALCHEMY_DATABASE_URI"]
|
|
|
3df609b |
try:
|
|
|
3df609b |
with patch("sys.argv", new=cli_cmd):
|
|
|
3df609b |
- manager_wrapper()
|
|
|
3df609b |
+ mbs_manager.cli()
|
|
|
3df609b |
finally:
|
|
|
3df609b |
app.config["SQLALCHEMY_DATABASE_URI"] = original_db_uri
|
|
|
3df609b |
|
|
|
3df609b |
|