From 6cebc873e248ce7816dd9e7b491d432caee9edbd Mon Sep 17 00:00:00 2001 From: Maximilian Moser Date: Fri, 17 Jul 2026 19:04:52 +0200 Subject: [PATCH 1/8] chore: fix some messages --- invenio_cli/cli/cli.py | 8 ++++---- invenio_cli/commands/requirements.py | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/invenio_cli/cli/cli.py b/invenio_cli/cli/cli.py index 81970e7..7f7c69d 100644 --- a/invenio_cli/cli/cli.py +++ b/invenio_cli/cli/cli.py @@ -59,11 +59,11 @@ def invenio_cli(ctx): help="Check requirements for a local development installation.", ) def check_requirements(development): - """Checks the system fulfills the pre-requirements.""" - click.secho("Checking pre-requirements...", fg="green") + """Checks the system fulfills the requirements.""" + click.secho("Checking requirements...", fg="green") steps = RequirementsCommands.check(development) - on_fail = "Pre requisites not met." - on_success = "All requisites are fulfilled." + on_fail = "Requirements not met." + on_success = "All requirements are fulfilled." run_steps(steps, on_fail, on_success) diff --git a/invenio_cli/commands/requirements.py b/invenio_cli/commands/requirements.py index f6d8ded..4d388fd 100644 --- a/invenio_cli/commands/requirements.py +++ b/invenio_cli/commands/requirements.py @@ -16,7 +16,7 @@ class RequirementsCommands(object): - """Pre-requirements check.""" + """Requirements check.""" @classmethod def _version_from_string(cls, string): From 9202ff4aa29a3556edd8bbb7f9027a3dede498c6 Mon Sep 17 00:00:00 2001 From: Maximilian Moser Date: Fri, 17 Jul 2026 19:05:53 +0200 Subject: [PATCH 2/8] fix: handle `FileNotFoundError` if `pipenv` is not installed * previously, `invenio-cli check-requirements` would crash if `pipenv` is not installed --- invenio_cli/commands/requirements.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/invenio_cli/commands/requirements.py b/invenio_cli/commands/requirements.py index 4d388fd..f976853 100644 --- a/invenio_cli/commands/requirements.py +++ b/invenio_cli/commands/requirements.py @@ -182,9 +182,13 @@ def check_pipenv_installed(cls): return ProcessResponse( output=f"Pipenv OK. Got version {version}.", status_code=0 ) - except Exception: + except FileNotFoundError: return ProcessResponse( - error=f"Pipenv not found. Got {result.error}.", status_code=1 + error=f"Pipenv not found.", status_code=1 + ) + except Exception as e: + return ProcessResponse( + error=f"Could not check for pipenv. Reason: {e}", status_code=1 ) @classmethod From f2daeb5011ef7f84d8f384626eefba3108d77225 Mon Sep 17 00:00:00 2001 From: Maximilian Moser Date: Fri, 17 Jul 2026 19:24:38 +0200 Subject: [PATCH 3/8] feat: extend `check-requirements` to also accept uv --- invenio_cli/commands/requirements.py | 41 ++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/invenio_cli/commands/requirements.py b/invenio_cli/commands/requirements.py index f976853..2c5eb1c 100644 --- a/invenio_cli/commands/requirements.py +++ b/invenio_cli/commands/requirements.py @@ -163,6 +163,39 @@ def check_git_version(cls, major, minor=-1, patch=-1, exact=False): status_code=1, ) + @classmethod + def check_python_pkg_manager_installed(cls): + """Check for uv or pipenv being available.""" + response = cls.check_uv_installed() + if response.status_code != 0: + response = cls.check_pipenv_installed() + + return response + + @classmethod + def check_uv_installed(cls): + """Check the uv version.""" + # Output comes in the form of: + # 'uv 0.11.29 (901092ee1 2026-07-15 x86_64-unknown-linux-gnu)\n' + try: + result = run_cmd(["uv", "--version"]) + tool, version, *_ = result.output.split(" ", 2) + if tool != "uv": + return ProcessResponse( + error=f"UV not found. Got {tool}.", status_code=1 + ) + else: + return ProcessResponse( + output=f"UV OK. Got version {version}.", status_code=0 + ) + + except FileNotFoundError: + return ProcessResponse(error=f"UV not found.", status_code=1) + except Exception as e: + return ProcessResponse( + error=f"Could not check for UV. Reason: {e}", status_code=1 + ) + @classmethod def check_pipenv_installed(cls): """Check the pipenv version.""" @@ -183,9 +216,7 @@ def check_pipenv_installed(cls): output=f"Pipenv OK. Got version {version}.", status_code=0 ) except FileNotFoundError: - return ProcessResponse( - error=f"Pipenv not found.", status_code=1 - ) + return ProcessResponse(error=f"Pipenv not found.", status_code=1) except Exception as e: return ProcessResponse( error=f"Could not check for pipenv. Reason: {e}", status_code=1 @@ -240,8 +271,8 @@ def check(cls, development=False): message="Checking Python version...", ), FunctionStep( - func=cls.check_pipenv_installed, - message="Checking Pipenv is installed...", + func=cls.check_python_pkg_manager_installed, + message="Checking if either UV or Pipenv are installed...", ), FunctionStep( func=cls.check_docker_version, From c2af4b5edded21cbc533441871e786be965fdc3e Mon Sep 17 00:00:00 2001 From: Maximilian Moser Date: Fri, 17 Jul 2026 19:37:28 +0200 Subject: [PATCH 4/8] feat: extend `check-requirements -d` to also consider PNPM --- invenio_cli/commands/requirements.py | 38 ++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/invenio_cli/commands/requirements.py b/invenio_cli/commands/requirements.py index 2c5eb1c..a976a81 100644 --- a/invenio_cli/commands/requirements.py +++ b/invenio_cli/commands/requirements.py @@ -79,13 +79,41 @@ def check_node_version(cls, major, minor=-1, patch=-1, exact=False): return ProcessResponse(error=f"Node not found. Got {err}.", status_code=1) @classmethod - def check_npm_version(cls, major, minor=-1, patch=-1, exact=False): + def check_js_pkg_manager_version(cls, **kwargs): + """Check the available version of pnpm or npm.""" + response = cls.check_pnpm_version(**kwargs) + if response.status_code != 0: + response = cls.check_npm_version(**kwargs) + + return response + + @classmethod + def check_pnpm_version( + cls, pnpm_major, pnpm_minor=-1, pnpm_patch=-1, pnpm_exact=False, **kwargs + ): + """Check the pnpm version.""" + # Output comes in the form of '11.3.0\n' + try: + result = run_cmd(["pnpm", "--version"]) + version = cls._version_from_string(result.output.strip()) + return cls._check_version( + "PNPM", version, pnpm_major, pnpm_minor, pnpm_patch, pnpm_exact + ) + except Exception as err: + return ProcessResponse(error=f"PNPM not found. Got {err}.", status_code=1) + + @classmethod + def check_npm_version( + cls, npm_major, npm_minor=-1, npm_patch=-1, npm_exact=False, **kwargs + ): """Check the npm version.""" # Output comes in the form of '6.14.13\n' try: result = run_cmd(["npm", "--version"]) version = cls._version_from_string(result.output.strip()) - return cls._check_version("NPM", version, major, minor, patch, exact) + return cls._check_version( + "NPM", version, npm_major, npm_minor, npm_patch, npm_exact + ) except Exception as err: return ProcessResponse(error=f"NPM not found. Got {err}.", status_code=1) @@ -243,9 +271,9 @@ def check_dev(cls): message="Checking Node version...", ), FunctionStep( - func=cls.check_npm_version, - args={"major": npm_version}, - message="Checking NPM version...", + func=cls.check_js_pkg_manager_version, + args={"npm_major": npm_version, "pnpm_major": 10}, + message="Checking if either PNPM or NPM are installed...", ), FunctionStep( func=cls.check_imagemagick_version, From bd50822f22ffbac95a4ef28f6e48a48d26ed2758 Mon Sep 17 00:00:00 2001 From: Maximilian Moser Date: Fri, 17 Jul 2026 19:57:04 +0200 Subject: [PATCH 5/8] fix: gracefully handle not finding a valid InvenioRDM project --- invenio_cli/commands/requirements.py | 31 ++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/invenio_cli/commands/requirements.py b/invenio_cli/commands/requirements.py index a976a81..c2c4221 100644 --- a/invenio_cli/commands/requirements.py +++ b/invenio_cli/commands/requirements.py @@ -250,13 +250,40 @@ def check_pipenv_installed(cls): error=f"Could not check for pipenv. Reason: {e}", status_code=1 ) + @classmethod + def report_error(cls, message): + """Function step that always fails with the specified message.""" + return lambda: ProcessResponse(error=message, status_code=1) + @classmethod def check_dev(cls): """Steps to check the development pre-requisites.""" - if rdm_version()[0] >= 12: + rdm_major_version = None + try: + if (version := rdm_version()) is not None: + rdm_major_version = version[0] + else: + return [ + FunctionStep( + func=cls.report_error( + "Could not find Invenio-App-RDM as dependency in the project definition." + ) + ) + ] + + except FileNotFoundError as e: + return [ + FunctionStep( + func=cls.report_error( + f"Could not determine the version of Invenio-App-RDM: {e}" + ) + ) + ] + + if rdm_major_version >= 12: node_version = 18 npm_version = 10 - elif rdm_version()[0] >= 11: + elif rdm_major_version >= 11: node_version = 16 npm_version = 7 else: From 9b260d8f61aac08ecb974c6b6a5ccc47cf72554a Mon Sep 17 00:00:00 2001 From: Maximilian Moser Date: Fri, 17 Jul 2026 19:58:46 +0200 Subject: [PATCH 6/8] chore: fix linter complaints about f-strings without placeholders --- invenio_cli/commands/requirements.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/invenio_cli/commands/requirements.py b/invenio_cli/commands/requirements.py index c2c4221..75782ce 100644 --- a/invenio_cli/commands/requirements.py +++ b/invenio_cli/commands/requirements.py @@ -218,7 +218,7 @@ def check_uv_installed(cls): ) except FileNotFoundError: - return ProcessResponse(error=f"UV not found.", status_code=1) + return ProcessResponse(error="UV not found.", status_code=1) except Exception as e: return ProcessResponse( error=f"Could not check for UV. Reason: {e}", status_code=1 @@ -244,7 +244,7 @@ def check_pipenv_installed(cls): output=f"Pipenv OK. Got version {version}.", status_code=0 ) except FileNotFoundError: - return ProcessResponse(error=f"Pipenv not found.", status_code=1) + return ProcessResponse(error="Pipenv not found.", status_code=1) except Exception as e: return ProcessResponse( error=f"Could not check for pipenv. Reason: {e}", status_code=1 From 2908782489f6399a9be6691b3633b4a2a062dc90 Mon Sep 17 00:00:00 2001 From: Maximilian Moser Date: Fri, 17 Jul 2026 20:24:49 +0200 Subject: [PATCH 7/8] chore: add node/npm minimum requirements for InvenioRDM v14 --- invenio_cli/commands/requirements.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/invenio_cli/commands/requirements.py b/invenio_cli/commands/requirements.py index 75782ce..b869684 100644 --- a/invenio_cli/commands/requirements.py +++ b/invenio_cli/commands/requirements.py @@ -280,7 +280,10 @@ def check_dev(cls): ) ] - if rdm_major_version >= 12: + if rdm_major_version >= 14: + node_version = 22 + npm_version = 10 + elif rdm_major_version >= 12: node_version = 18 npm_version = 10 elif rdm_major_version >= 11: From 43a6e1ca503f9ddf20fa2b88a841a6230bda56be Mon Sep 17 00:00:00 2001 From: Maximilian Moser Date: Fri, 17 Jul 2026 20:33:47 +0200 Subject: [PATCH 8/8] fix: show available version as string instead of integer array * previously we were displaying the parsed `parts` (integer array) instead of the original string representation of the `version`, which resulted in weird-looking output --- invenio_cli/commands/requirements.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/invenio_cli/commands/requirements.py b/invenio_cli/commands/requirements.py index b869684..fd1e9f1 100644 --- a/invenio_cli/commands/requirements.py +++ b/invenio_cli/commands/requirements.py @@ -63,7 +63,7 @@ def _check_version(cls, binary, version, major, minor=-1, patch=-1, exact=False) expected_version = f"{major}.{minor}.{patch}" return ProcessResponse( - error=f"{binary} wrong version." f"Got {parts} expected {expected_version}", + error=f"{binary} wrong version. Got {version}, expected {expected_version}", status_code=1, )