Skip to content
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
8 changes: 8 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@
Changes
=======

Version 1.6.0 (released 2025-02-28)

- packages: allow use of either `pipenv` or `uv` as python package manager
- flask: replace `FLASK_ENV` with `FLASK_DEBUG`
- celery: allow setting a log level
- config: make host & port for both web and search configurable via `.invenio.private`
- run: introduce more fine-granular "web" and "worker" sub-commands

Version 1.5.0 (released 2024-08-01)

- dependencies: update for invenio-app-rdm v12
Expand Down
2 changes: 0 additions & 2 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@

from __future__ import print_function

import sphinx.environment

from invenio_cli import __version__

# -- General configuration ------------------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion invenio_cli/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@
"""Invenio module to ease the creation and management of applications."""


__version__ = "1.5.0"
__version__ = "1.6.0"

__all__ = ("__version__",)
145 changes: 116 additions & 29 deletions invenio_cli/cli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
# Copyright (C) 2019-2021 CERN.
# Copyright (C) 2019 Northwestern University.
# Copyright (C) 2022 Forschungszentrum Jülich GmbH.
# Copyright (C) 2024-2025 Graz University of Technology.
#
# Invenio-Cli is free software; you can redistribute it and/or modify it
# under the terms of the MIT License; see LICENSE file for more details.
Expand Down Expand Up @@ -30,7 +31,12 @@
from .packages import packages
from .services import services
from .translations import translations
from .utils import handle_process_response, pass_cli_config, run_steps
from .utils import (
combine_decorators,
handle_process_response,
pass_cli_config,
run_steps,
)


@click.group()
Expand Down Expand Up @@ -67,9 +73,10 @@ def check_requirements(development):


@invenio_cli.command()
def shell():
@pass_cli_config
def shell(cli_config):
"""Shell command."""
Commands.shell()
Commands(cli_config).shell()


@invenio_cli.command()
Expand All @@ -80,9 +87,10 @@ def shell():
is_flag=True,
help="Enable Flask development mode (default: disabled).",
)
def pyshell(debug):
@pass_cli_config
def pyshell(cli_config, debug):
"""Python shell command."""
Commands.pyshell(debug=debug)
Commands(cli_config).pyshell(debug=debug)


@invenio_cli.command()
Expand All @@ -104,8 +112,7 @@ def pyshell(debug):
@click.option(
"--user-input/--no-input",
default=True,
help="If input is disabled, uses the defaults (if --config is"
" also passed, uses values from an .invenio config file).",
help="If input is disabled, uses the defaults (if --config is also passed, uses values from an .invenio config file).", # noqa
)
@click.option(
"--config", required=False, help="The .invenio configuration file to use."
Expand Down Expand Up @@ -142,48 +149,127 @@ def init(flavour, template, checkout, user_input, config):
cookiecutter_wrapper.remove_config()


@invenio_cli.command()
@click.option("--host", "-h", default="127.0.0.1", help="The interface to bind to.")
@click.option("--port", "-p", default=5000, help="The port to bind to.")
@click.option(
"--debug/--no-debug",
"-d/",
default=True,
is_flag=True,
help="Enable/disable debug mode including auto-reloading " "(default: enabled).",
)
@click.option(
@invenio_cli.group("run", invoke_without_command=True)
@click.pass_context
def run_group(ctx):
"""Run command group."""
# For backward compatibility
if ctx.invoked_subcommand is None:
ctx.invoke(run_all)


services_option = click.option(
"--services/--no-services",
"-s/-n",
default=True,
is_flag=True,
help="Enable/disable dockerized services (default: enabled).",
)
@click.option(
"--celery-log-file",
default=None,
help="Celery log file (default: None, this means logging to stderr)",
web_options = combine_decorators(
click.option(
"--host",
"-h",
default=None,
help="The interface to bind to. The default is defined in the CLIConfig.",
),
click.option(
"--port",
"-p",
default=None,
help="The port to bind to. The default is defined in the CLIConfig.",
),
click.option(
"--debug/--no-debug",
"-d/",
default=True,
is_flag=True,
help="Enable/disable debug mode including auto-reloading (default: enabled).",
),
)


@run_group.command("web")
@services_option
@web_options
@pass_cli_config
def run(cli_config, host, port, debug, services, celery_log_file):
"""Starts the local development server.
def run_web(cli_config, host, port, debug, services):
"""Starts the local development web server."""
if services:
cmds = ServicesCommands(cli_config)
response = cmds.ensure_containers_running()
# fail and exit if containers are not running
handle_process_response(response)

host = host or cli_config.get_web_host()
port = port or cli_config.get_web_port()

commands = LocalCommands(cli_config)
processes = commands.run_web(host=host, port=str(port), debug=debug)
for proc in processes:
proc.wait()


worker_options = combine_decorators(
click.option(
"--celery-log-file",
default=None,
help="Celery log file (default: None, this means logging to stderr)",
),
click.option(
"--celery-log-level",
default="INFO",
help="Celery log level (default: INFO)",
),
)


@run_group.command("worker")
@services_option
@worker_options
@pass_cli_config
def run_worker(cli_config, services, celery_log_file, celery_log_level):
"""Starts the local development server."""
if services:
cmds = ServicesCommands(cli_config)
response = cmds.ensure_containers_running()
# fail and exit if containers are not running
handle_process_response(response)

commands = LocalCommands(cli_config)
processes = commands.run_worker(
celery_log_file=celery_log_file, celery_log_level=celery_log_level
)
for proc in processes:
proc.wait()


NOTE: this only makes sense locally so no --local option
"""
@run_group.command("all")
@services_option
@web_options
@worker_options
@pass_cli_config
def run_all(cli_config, host, port, debug, services, celery_log_file, celery_log_level):
"""Starts web and worker development servers."""
if services:
cmds = ServicesCommands(cli_config)
response = cmds.ensure_containers_running()
# fail and exit if containers are not running
handle_process_response(response)

host = host or cli_config.get_web_host()
port = port or cli_config.get_web_port()

commands = LocalCommands(cli_config)
commands.run(
processes = commands.run_all(
host=host,
port=str(port),
debug=debug,
services=services,
celery_log_file=celery_log_file,
celery_log_level=celery_log_level,
)
for proc in processes:
proc.wait()


@invenio_cli.command()
Expand All @@ -206,9 +292,10 @@ def destroy(cli_config):

@invenio_cli.command()
@click.option("--script", required=True, help="The path of custom migration script.")
def upgrade(script):
@pass_cli_config
def upgrade(cli_config, script):
"""Upgrades the current instance to a newer version."""
steps = UpgradeCommands.upgrade(script)
steps = UpgradeCommands(cli_config).upgrade(script)
on_fail = "Upgrade failed."
on_success = "Upgrade sucessfull."

Expand Down
74 changes: 69 additions & 5 deletions invenio_cli/cli/install.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,16 @@
from .utils import pass_cli_config, run_steps


@click.command()
@click.group(invoke_without_command=True)
@click.pass_context
def install(ctx):
"""Commands for installing the project."""
if ctx.invoked_subcommand is None:
# If no sub-command is passed, default to the install all command.
ctx.invoke(install_all)


@install.command("all")
@click.option(
"--pre",
default=False,
Expand All @@ -31,12 +40,11 @@
"-p/-d",
default=False,
is_flag=True,
help="Production mode copies statics/assets. Development mode symlinks"
" statics/assets.",
help="Production mode copies statics/assets. Development mode symlinks them.",
)
@pass_cli_config
def install(cli_config, pre, dev, production):
"""Installs the project locally.
def install_all(cli_config, pre, dev, production):
"""Installs the project locally.

Installs dependencies, creates instance directory,
links invenio.cfg + templates, copies images and other statics and finally
Expand All @@ -52,3 +60,59 @@ def install(cli_config, pre, dev, production):
on_success = "Dependencies installed successfully."

run_steps(steps, on_fail, on_success)


@install.command("python")
@click.option(
"--pre",
default=False,
is_flag=True,
help="If specified, allows the installation of alpha releases",
)
@click.option(
"--dev/--no-dev",
default=True,
is_flag=True,
help="Includes development dependencies.",
)
@pass_cli_config
def install_python(cli_config, pre, dev):
"""Install Python dependencies and packages."""
commands = InstallCommands(cli_config)
steps = commands.install_py_dependencies(pre=pre, dev=dev)
on_fail = "Failed to install Python dependencies."
on_success = "Python dependencies installed successfully."

run_steps(steps, on_fail, on_success)


@install.command("assets")
@click.option(
"--production/--development",
"-p/-d",
default=False,
is_flag=True,
help="Production mode copies statics/assets. Development mode symlinks them.",
)
@pass_cli_config
def install_assets(cli_config, production):
"""Install assets."""
commands = InstallCommands(cli_config)
flask_env = "production" if production else "development"
steps = commands.install_assets(flask_env)
on_fail = "Failed to install assets."
on_success = "Assets installed successfully."

run_steps(steps, on_fail, on_success)


@install.command()
@pass_cli_config
def symlink(cli_config):
"""Symlinks project files in the instance directory."""
commands = InstallCommands(cli_config)
steps = commands.symlink()
on_fail = "Failed to symlink project files and folders."
on_success = "Project files and folders symlinked successfully."

run_steps(steps, on_fail, on_success)
14 changes: 8 additions & 6 deletions invenio_cli/cli/packages.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2020-2021 CERN.
# Copyright (C) 2022 Graz University of Technology.
# Copyright (C) 2022-2025 Graz University of Technology.
#
# Invenio-Cli is free software; you can redistribute it and/or modify it
# under the terms of the MIT License; see LICENSE file for more details.
Expand Down Expand Up @@ -34,7 +34,7 @@ def lock(cli_config, pre, dev):
+ f"Include dev-packages: {dev}.",
fg="green",
)
steps = PackagesCommands.lock(pre, dev)
steps = PackagesCommands(cli_config).lock(pre, dev)
on_fail = "Failed to lock dependencies."
on_success = "Dependencies locked successfully."

Expand All @@ -58,7 +58,7 @@ def install(cli_config, packages, skip_build, pip_log_file, node_log_file):
if len(packages) < 1:
raise click.UsageError("You must specify at least one package.")

steps = PackagesCommands.install_packages(packages, pip_log_file)
steps = PackagesCommands(cli_config).install_packages(packages, pip_log_file)

on_fail = f"Failed to install packages {packages}."
on_success = f"Packages {packages} installed successfully."
Expand All @@ -77,7 +77,7 @@ def install(cli_config, packages, skip_build, pip_log_file, node_log_file):
@pass_cli_config
def outdated(cli_config):
"""Show outdated Python dependencies."""
steps = PackagesCommands.outdated_packages()
steps = PackagesCommands(cli_config).outdated_packages()

on_fail = "Some of the packages need to be updated."
on_success = "All packages are up to date."
Expand All @@ -94,11 +94,13 @@ def update(cli_config, version=None):
db = cli_config.get_db_type()
search = cli_config.get_search_type()
package = f"invenio-app-rdm[{db},{search}]~="
steps = PackagesCommands.update_package_new_version(package, version)
steps = PackagesCommands(cli_config).update_package_new_version(
package, version
)
on_fail = f"Failed to update version {version}"
on_success = f"Version {version} installed successfully."
else:
steps = PackagesCommands.update_packages()
steps = PackagesCommands(cli_config).update_packages()
on_fail = "Failed to update packages."
on_success = "Packages installed successfully."

Expand Down
Loading