2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-06-13 18:45:40 +00:00

feat(backend): Add check to cli tools to confirm the right commands for deployment method are used (#9687)

* refactor

* rename functions

* move checking for a package install out

* [FR] Add check to cli tools to confirm the right commands for deployment method are used
Fixes #9684

* also log pkg enviroment detection

* vendor is_true

* ensure content is loaded in pkg enviroment

* fix tests and imporve error message

* cleanup

* simplify

* ensure runs in misconfed enviroment
This commit is contained in:
Matthias Mair
2025-05-21 22:16:50 +02:00
committed by GitHub
parent 2fbd01a110
commit f6283dfcc4
2 changed files with 95 additions and 31 deletions

View File

@ -99,6 +99,13 @@ There are database migrations waiting to be applied. This might lead to integrit
Some deployment methods support [auto applying of updates](../start/config.md#auto-update). See also [Perform Database Migrations](../start/install.md#perform-database-migrations).
Steps very between deployment methods.
#### INVE-W9
**Wrong Invoke Environment - Backend**
The command that was used to run invoke is not the one that is recommended. This might be caused by a wrong PATH variable or by thinking you are using a different deployment method.
The warning text will show the recommended command for intended use.
### INVE-I (InvenTree Information)
Information — These are not errors but information messages. They might point out potential issues or just provide information.

119
tasks.py
View File

@ -17,29 +17,65 @@ from invoke import Collection, task
from invoke.exceptions import UnexpectedExit
def is_true(x):
"""Shortcut function to determine if a value "looks" like a boolean."""
return str(x).strip().lower() in ['1', 'y', 'yes', 't', 'true', 'on']
def is_docker_environment():
"""Check if the InvenTree environment is running in a Docker container."""
from src.backend.InvenTree.InvenTree.config import is_true
return is_true(os.environ.get('INVENTREE_DOCKER', 'False'))
def is_rtd_environment():
"""Check if the InvenTree environment is running on ReadTheDocs."""
from src.backend.InvenTree.InvenTree.config import is_true
return is_true(os.environ.get('READTHEDOCS', 'False'))
def is_debug_environment():
"""Check if the InvenTree environment is running in a debug environment."""
from src.backend.InvenTree.InvenTree.config import is_true
return is_true(os.environ.get('INVENTREE_DEBUG', 'False')) or is_true(
os.environ.get('RUNNER_DEBUG', 'False')
)
def get_version_vals():
"""Get values from the VERSION file."""
version_file = local_dir().joinpath('VERSION')
if not version_file.exists():
return {}
try:
from dotenv import dotenv_values
return dotenv_values(version_file)
except ImportError:
error(
'ERROR: dotenv package not installed. You might not be running in the right environment.'
)
return {}
def is_pkg_installer(content: Optional[dict] = None, load_content: bool = False):
"""Check if the current environment is a package installer by VERSION/environment."""
if load_content:
content = get_version_vals()
return get_installer(content) == 'PKG'
def is_pkg_installer_by_path():
"""Check if the current environment is a package installer by checking the path."""
return len(sys.argv) >= 1 and sys.argv[0].startswith(
'/opt/inventree/env/bin/invoke'
)
def get_installer(content: Optional[dict] = None):
"""Get the installer for the current environment or a content dict."""
if content is None:
content = os.environ
return content.get('INVENTREE_PKG_INSTALLER', None)
# region execution logging helpers
def task_exception_handler(t, v, tb):
"""Handle exceptions raised by tasks.
@ -121,9 +157,9 @@ def state_logger(fn=None, method_name=None):
# region environment checks
def check_invoke_version():
def envcheck_invoke_version():
"""Check that the installed invoke version meets minimum requirements."""
MIN_INVOKE_VERSION = '2.0.0'
MIN_INVOKE_VERSION: str = '2.0.0'
min_version = tuple(map(int, MIN_INVOKE_VERSION.split('.')))
invoke_version = tuple(map(int, invoke.__version__.split('.'))) # noqa: RUF048
@ -134,14 +170,14 @@ def check_invoke_version():
sys.exit(1)
def check_invoke_path():
def envcheck_invoke_path():
"""Check that the path of the used invoke is correct."""
if is_docker_environment() or is_rtd_environment():
return
invoke_path = Path(invoke.__file__)
env_path = Path(sys.prefix).resolve()
loc_path = Path(__file__).parent.resolve()
invoke_path: Path = Path(invoke.__file__)
env_path: Path = Path(sys.prefix).resolve()
loc_path: Path = Path(__file__).parent.resolve()
if not invoke_path.is_relative_to(loc_path) and not invoke_path.is_relative_to(
env_path
):
@ -152,17 +188,17 @@ def check_invoke_path():
sys.exit(1)
def check_python_version():
def envcheck_python_version():
"""Check that the installed python version meets minimum requirements.
If the python version is not sufficient, exits with a non-zero exit code.
"""
REQ_MAJOR = 3
REQ_MINOR = 9
REQ_MAJOR: int = 3
REQ_MINOR: int = 9
version = sys.version.split(' ')[0]
valid = True
valid: bool = True
if sys.version_info.major < REQ_MAJOR or (
sys.version_info.major == REQ_MAJOR and sys.version_info.minor < REQ_MINOR
@ -175,10 +211,35 @@ def check_python_version():
sys.exit(1)
if __name__ in ['__main__', 'tasks']:
check_invoke_version()
check_invoke_path()
check_python_version()
def envcheck_invoke_cmd():
"""Checks if the rights invoke command for the current environment is used."""
first_cmd = sys.argv[0].replace(sys.prefix, '')
intendded = ['/bin/invoke', '/bin/inv']
correct_cmd: Optional[str] = None
if is_rtd_environment() or is_docker_environment():
pass
elif is_pkg_installer(load_content=True) and not is_pkg_installer_by_path():
correct_cmd = 'inventree run invoke'
else:
warning('Unknown environment, not checking used invoke command')
if first_cmd not in intendded:
correct_cmd = correct_cmd if correct_cmd else 'invoke'
error('INVE-W9 - Wrong Invoke Environment')
error(
f'The detected invoke command `{first_cmd}` is not the intended one for this environment, ensure you are using one of the following command(s) `{correct_cmd}`'
)
def main():
"""Main function to check the execution environment."""
envcheck_invoke_version()
envcheck_python_version()
envcheck_invoke_path()
envcheck_invoke_cmd()
# endregion
@ -279,6 +340,9 @@ def manage_py_path():
# endregion
if __name__ in ['__main__', 'tasks']:
main()
def run(c, cmd, path: Optional[Path] = None, pty=False, env=None):
"""Runs a given command a given path.
@ -1399,11 +1463,12 @@ Yarn {yarn if yarn else NA}
Environment:
Docker {is_docker_environment()}
RTD {is_rtd_environment()}
PKG {is_pkg_installer()}
Commit hash: {InvenTreeVersion.inventreeCommitHash()}
Commit date: {InvenTreeVersion.inventreeCommitDate()}"""
)
if len(sys.argv) == 1 and sys.argv[0].startswith('/opt/inventree/env/lib/python'):
if is_pkg_installer_by_path():
print(
"""
You are probably running the package installer / single-line installer. Please mention this in any bug reports!
@ -1622,16 +1687,8 @@ def frontend_download(
).strip()
except Exception:
# .deb Packages contain extra information in the VERSION file
version_file = local_dir().joinpath('VERSION')
if not version_file.exists():
return
from dotenv import dotenv_values
content = dotenv_values(version_file)
if (
'INVENTREE_PKG_INSTALLER' in content
and content['INVENTREE_PKG_INSTALLER'] == 'PKG'
):
content: dict = get_version_vals()
if is_pkg_installer(content):
ref = content.get('INVENTREE_COMMIT_SHA')
info(
f'[INFO] Running in package environment, got commit "{ref}" from VERSION file'