From b2587848047cb74cbd4a0dfc90d1a26bd55c797f Mon Sep 17 00:00:00 2001 From: Sam Arbid Date: Thu, 3 Apr 2025 12:40:31 +0200 Subject: [PATCH 1/6] config: add support for custom package managers in CLI configuration --- invenio_cli/helpers/cli_config.py | 10 ++++++- tests/helpers/test_cli_config.py | 47 +++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/invenio_cli/helpers/cli_config.py b/invenio_cli/helpers/cli_config.py index 3592cbe..8de9132 100644 --- a/invenio_cli/helpers/cli_config.py +++ b/invenio_cli/helpers/cli_config.py @@ -2,6 +2,7 @@ # SPDX-FileCopyrightText: 2019-2020 Northwestern University. # SPDX-FileCopyrightText: 2021 Esteban J. G. Gabancho. # SPDX-FileCopyrightText: 2024 Graz University of Technology. +# SPDX-FileCopyrightText: 2025-2026 KTH Royal Institute of Technology. # SPDX-License-Identifier: MIT """Invenio-cli configuration file.""" @@ -223,11 +224,18 @@ def write(cls, project_dir, flavour, replay): config_parser[cls.CLI_SECTION] = {} config_parser[cls.CLI_SECTION]["flavour"] = flavour config_parser[cls.CLI_SECTION]["logfile"] = "/logs/invenio-cli.log" - + custom_package_managers = { + "javascript_package_manager": replay.get("cookiecutter").get( + "javascript_package_manager", None + ), + } # Cookiecutter user input section config_parser[cls.COOKIECUTTER_SECTION] = {} for key, value in replay[cls.COOKIECUTTER_SECTION].items(): config_parser[cls.COOKIECUTTER_SECTION][key] = str(value) + # Set the package managers in the CLI section + if custom_package_managers.get(key) == "pnpm": + config_parser[cls.CLI_SECTION][key] = value # Generated files section config_parser[cls.FILES_SECTION] = get_created_files(project_dir) diff --git a/tests/helpers/test_cli_config.py b/tests/helpers/test_cli_config.py index 071b64e..543734e 100644 --- a/tests/helpers/test_cli_config.py +++ b/tests/helpers/test_cli_config.py @@ -1,11 +1,13 @@ # SPDX-FileCopyrightText: 2019-2020 CERN. # SPDX-FileCopyrightText: 2019-2021 Northwestern University. +# SPDX-FileCopyrightText: 2025-2026 KTH Royal Institute of Technology. # SPDX-License-Identifier: MIT """Module config_file tests.""" import os import tempfile +from configparser import ConfigParser from pathlib import Path import pytest @@ -116,3 +118,48 @@ def test_cli_config_get_project_shortname(config_dir): cli_config = CLIConfig(config_dir) assert cli_config.get_project_shortname() == "my-site" + + +@pytest.mark.parametrize( + "package_manager, expected_in_cli", + [ + ("pnpm", True), + ("npm", False), + (None, False), + ], +) +def test_javascript_package_manager_config(package_manager, expected_in_cli, tmpdir): + """Test JavaScript package manager is correctly set in CLI config.""" + project_dir = tmpdir.mkdir("test-project") + flavour = "RDM" + replay = { + "cookiecutter": { + "project_name": "My Site", + "project_shortname": "my-site", + "project_site": "my-site.com", + "github_repo": "my-site/my-site", + "description": "Invenio RDM My Site Instance", + "author_name": "CERN", + "author_email": "info@my-site.com", + "year": "2022", + "database": "postgresql", + "search": "opensearch1", + "_template": "https://github.com/inveniosoftware/cookiecutter-invenio-rdm.git", # noqa + } + } + if package_manager is not None: + replay["cookiecutter"]["javascript_package_manager"] = package_manager + + CLIConfig.write(str(project_dir), flavour, replay) + + config = ConfigParser() + config_path = project_dir.join(CLIConfig.CONFIG_FILENAME) + config.read(str(config_path)) + + if expected_in_cli: + assert config.has_option(CLIConfig.CLI_SECTION, "javascript_package_manager") + assert config.get(CLIConfig.CLI_SECTION, "javascript_package_manager") == "pnpm" + else: + assert not config.has_option( + CLIConfig.CLI_SECTION, "javascript_package_manager" + ) From d876669ff3f6e171a3f9f4d8ea8c6782ad8435da Mon Sep 17 00:00:00 2001 From: Sam Arbid Date: Thu, 12 Feb 2026 09:24:40 +0100 Subject: [PATCH 2/6] feat: default js package manager to PNPM * adjust CLI configuration to set PNPM as the default JS package manager As discussed in the Telecon. * Update tests to match the new default --- invenio_cli/helpers/cli_config.py | 12 +++--------- tests/helpers/test_cli_config.py | 24 ++++-------------------- 2 files changed, 7 insertions(+), 29 deletions(-) diff --git a/invenio_cli/helpers/cli_config.py b/invenio_cli/helpers/cli_config.py index 8de9132..4662188 100644 --- a/invenio_cli/helpers/cli_config.py +++ b/invenio_cli/helpers/cli_config.py @@ -96,7 +96,7 @@ def javascript_package_manager(self) -> JavascriptPackageManager: elif manager_name == PNPM.name: return PNPM() - return NPM() + return PNPM() def get_project_dir(self): """Returns path to project directory.""" @@ -224,18 +224,12 @@ def write(cls, project_dir, flavour, replay): config_parser[cls.CLI_SECTION] = {} config_parser[cls.CLI_SECTION]["flavour"] = flavour config_parser[cls.CLI_SECTION]["logfile"] = "/logs/invenio-cli.log" - custom_package_managers = { - "javascript_package_manager": replay.get("cookiecutter").get( - "javascript_package_manager", None - ), - } + config_parser[cls.CLI_SECTION]["javascript_package_manager"] = PNPM.name + # Cookiecutter user input section config_parser[cls.COOKIECUTTER_SECTION] = {} for key, value in replay[cls.COOKIECUTTER_SECTION].items(): config_parser[cls.COOKIECUTTER_SECTION][key] = str(value) - # Set the package managers in the CLI section - if custom_package_managers.get(key) == "pnpm": - config_parser[cls.CLI_SECTION][key] = value # Generated files section config_parser[cls.FILES_SECTION] = get_created_files(project_dir) diff --git a/tests/helpers/test_cli_config.py b/tests/helpers/test_cli_config.py index 543734e..83740f7 100644 --- a/tests/helpers/test_cli_config.py +++ b/tests/helpers/test_cli_config.py @@ -120,16 +120,8 @@ def test_cli_config_get_project_shortname(config_dir): assert cli_config.get_project_shortname() == "my-site" -@pytest.mark.parametrize( - "package_manager, expected_in_cli", - [ - ("pnpm", True), - ("npm", False), - (None, False), - ], -) -def test_javascript_package_manager_config(package_manager, expected_in_cli, tmpdir): - """Test JavaScript package manager is correctly set in CLI config.""" +def test_javascript_package_manager_config(tmpdir): + """Test JavaScript package manager defaults to pnpm in CLI config.""" project_dir = tmpdir.mkdir("test-project") flavour = "RDM" replay = { @@ -147,19 +139,11 @@ def test_javascript_package_manager_config(package_manager, expected_in_cli, tmp "_template": "https://github.com/inveniosoftware/cookiecutter-invenio-rdm.git", # noqa } } - if package_manager is not None: - replay["cookiecutter"]["javascript_package_manager"] = package_manager - CLIConfig.write(str(project_dir), flavour, replay) config = ConfigParser() config_path = project_dir.join(CLIConfig.CONFIG_FILENAME) config.read(str(config_path)) - if expected_in_cli: - assert config.has_option(CLIConfig.CLI_SECTION, "javascript_package_manager") - assert config.get(CLIConfig.CLI_SECTION, "javascript_package_manager") == "pnpm" - else: - assert not config.has_option( - CLIConfig.CLI_SECTION, "javascript_package_manager" - ) + assert config.has_option(CLIConfig.CLI_SECTION, "javascript_package_manager") + assert config.get(CLIConfig.CLI_SECTION, "javascript_package_manager") == "pnpm" From e55beb7cb2d98bc9325e935a7055f0e6aeda38d9 Mon Sep 17 00:00:00 2001 From: Sam Arbid Date: Thu, 12 Feb 2026 11:24:22 +0100 Subject: [PATCH 3/6] fix: update search type handling in CLI config * Simplify the get_search_type method to return a default value. * Remove hardcoded search type from test configurations. --- invenio_cli/helpers/cli_config.py | 6 ++---- tests/helpers/test_cli_config.py | 3 --- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/invenio_cli/helpers/cli_config.py b/invenio_cli/helpers/cli_config.py index 4662188..54abecf 100644 --- a/invenio_cli/helpers/cli_config.py +++ b/invenio_cli/helpers/cli_config.py @@ -171,7 +171,7 @@ def get_db_type(self): return self.config[CLIConfig.COOKIECUTTER_SECTION]["database"] def get_search_type(self): - """Returns the search type (opensearch1, elasticsearch7).""" + """Returns the search type.""" sections = self.config[CLIConfig.COOKIECUTTER_SECTION] if "elasticsearch" in sections: # cookiecutter < v10 @@ -181,9 +181,7 @@ def get_search_type(self): # cookiecutter >= v10 return sections["search"] else: - raise InvenioCLIConfigError( - "`search` or `elasticsearch` field not set in .invenio file" - ) + return "opensearch2" def get_file_storage(self): """Returns the file storage (local, s3, etc.).""" diff --git a/tests/helpers/test_cli_config.py b/tests/helpers/test_cli_config.py index 83740f7..b0f8e5e 100644 --- a/tests/helpers/test_cli_config.py +++ b/tests/helpers/test_cli_config.py @@ -32,7 +32,6 @@ def test_cli_config_write(): "author_email": "info@my-site.com", "year": "2022", "database": "postgresql", - "search": "opensearch1", "_template": "https://github.com/inveniosoftware/cookiecutter-invenio-rdm.git", # noqa } } @@ -65,7 +64,6 @@ def config_dir(): "author_email": "info@my-site.com", "year": "2022", "database": "postgresql", - "search": "opensearch1", "_template": "https://github.com/inveniosoftware/cookiecutter-invenio-rdm.git", # noqa } } @@ -135,7 +133,6 @@ def test_javascript_package_manager_config(tmpdir): "author_email": "info@my-site.com", "year": "2022", "database": "postgresql", - "search": "opensearch1", "_template": "https://github.com/inveniosoftware/cookiecutter-invenio-rdm.git", # noqa } } From de5649d27056b88563b4990d127a5dd35d9fe8df Mon Sep 17 00:00:00 2001 From: Sam Arbid Date: Thu, 12 Feb 2026 11:37:07 +0100 Subject: [PATCH 4/6] fix: simplify get_search_type method * Refactored get_search_type to a static method. * Removed legacy search type handling for compatibility. * Updated tests to verify new search type behavior. --- invenio_cli/helpers/cli_config.py | 17 ++++++----------- tests/helpers/test_cli_config.py | 3 ++- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/invenio_cli/helpers/cli_config.py b/invenio_cli/helpers/cli_config.py index 54abecf..8badce3 100644 --- a/invenio_cli/helpers/cli_config.py +++ b/invenio_cli/helpers/cli_config.py @@ -170,18 +170,10 @@ def get_db_type(self): """Returns the database type (mysql, postgresql).""" return self.config[CLIConfig.COOKIECUTTER_SECTION]["database"] - def get_search_type(self): + @staticmethod + def get_search_type(): """Returns the search type.""" - sections = self.config[CLIConfig.COOKIECUTTER_SECTION] - if "elasticsearch" in sections: - # cookiecutter < v10 - version = sections["elasticsearch"] - return f"elasticsearch{version}" - elif "search" in sections: - # cookiecutter >= v10 - return sections["search"] - else: - return "opensearch2" + return "opensearch2" def get_file_storage(self): """Returns the file storage (local, s3, etc.).""" @@ -228,6 +220,9 @@ def write(cls, project_dir, flavour, replay): config_parser[cls.COOKIECUTTER_SECTION] = {} for key, value in replay[cls.COOKIECUTTER_SECTION].items(): config_parser[cls.COOKIECUTTER_SECTION][key] = str(value) + # Keep compatibility with older tooling that expects `search` to exist. + # Search backend choice has been removed and opensearch2 is fixed. + config_parser[cls.COOKIECUTTER_SECTION]["search"] = cls.get_search_type() # Generated files section config_parser[cls.FILES_SECTION] = get_created_files(project_dir) diff --git a/tests/helpers/test_cli_config.py b/tests/helpers/test_cli_config.py index b0f8e5e..f578ec2 100644 --- a/tests/helpers/test_cli_config.py +++ b/tests/helpers/test_cli_config.py @@ -1,6 +1,6 @@ # SPDX-FileCopyrightText: 2019-2020 CERN. # SPDX-FileCopyrightText: 2019-2021 Northwestern University. -# SPDX-FileCopyrightText: 2025-2026 KTH Royal Institute of Technology. +# SPDX-FileCopyrightText: 2025-2026-2026 KTH Royal Institute of Technology. # SPDX-License-Identifier: MIT """Module config_file tests.""" @@ -144,3 +144,4 @@ def test_javascript_package_manager_config(tmpdir): assert config.has_option(CLIConfig.CLI_SECTION, "javascript_package_manager") assert config.get(CLIConfig.CLI_SECTION, "javascript_package_manager") == "pnpm" + assert config.get(CLIConfig.COOKIECUTTER_SECTION, "search") == "opensearch2" From 8cea6d1c8d5ec58befdc2c3b303d2ec8b83f3af5 Mon Sep 17 00:00:00 2001 From: Sam Arbid Date: Mon, 15 Jun 2026 22:06:13 +0200 Subject: [PATCH 5/6] cli: fix db type to 'postgresql' in config * keep only 'postgresql' in CLIConfig as options. * Adjust tests to reflect new database and search configurations. --- invenio_cli/cli/containers.py | 2 +- invenio_cli/cli/services.py | 2 +- invenio_cli/helpers/cli_config.py | 12 +++++++----- tests/helpers/test_cli_config.py | 10 ++++------ 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/invenio_cli/cli/containers.py b/invenio_cli/cli/containers.py index 0212bb7..1517dcd 100644 --- a/invenio_cli/cli/containers.py +++ b/invenio_cli/cli/containers.py @@ -100,7 +100,7 @@ def setup(cli_config, force, no_demo_data, stop_services, services): def status(ctx, verbose): """Checks if the services are up and running. - NOTE: currently only search, DB (postgresql/mysql) and redis are supported. + NOTE: currently only search (opensearch2), DB (postgresql) and redis are supported. """ ctx.invoke(services_status_cmd, verbose=verbose) diff --git a/invenio_cli/cli/services.py b/invenio_cli/cli/services.py index b85176e..69fce1f 100644 --- a/invenio_cli/cli/services.py +++ b/invenio_cli/cli/services.py @@ -86,7 +86,7 @@ def setup(cli_config, force, no_demo_data, stop_services, services): def status(cli_config, verbose): """Checks if the services are up and running. - NOTE: currently only search (OS/ES), DB (postgresql/mysql) and redis are supported. + NOTE: currently only search (opensearch2), DB (postgresql) and redis are supported. """ commands = ServicesCommands(cli_config) services = ["redis", cli_config.get_db_type(), "search"] diff --git a/invenio_cli/helpers/cli_config.py b/invenio_cli/helpers/cli_config.py index 8badce3..8a0102d 100644 --- a/invenio_cli/helpers/cli_config.py +++ b/invenio_cli/helpers/cli_config.py @@ -166,9 +166,10 @@ def get_web_host(self): """Returns web host.""" return self.private_config[CLIConfig.CLI_SECTION].get("web_host", "127.0.0.1") - def get_db_type(self): - """Returns the database type (mysql, postgresql).""" - return self.config[CLIConfig.COOKIECUTTER_SECTION]["database"] + @staticmethod + def get_db_type(): + """Returns the database type.""" + return "postgresql" @staticmethod def get_search_type(): @@ -220,8 +221,9 @@ def write(cls, project_dir, flavour, replay): config_parser[cls.COOKIECUTTER_SECTION] = {} for key, value in replay[cls.COOKIECUTTER_SECTION].items(): config_parser[cls.COOKIECUTTER_SECTION][key] = str(value) - # Keep compatibility with older tooling that expects `search` to exist. - # Search backend choice has been removed and opensearch2 is fixed. + # Keep compatibility with older tooling that expects `database` and `search` to exist. + # Backend choice has been removed; PostgreSQL and OpenSearch2 are fixed. + config_parser[cls.COOKIECUTTER_SECTION]["database"] = cls.get_db_type() config_parser[cls.COOKIECUTTER_SECTION]["search"] = cls.get_search_type() # Generated files section diff --git a/tests/helpers/test_cli_config.py b/tests/helpers/test_cli_config.py index f578ec2..3eabbfa 100644 --- a/tests/helpers/test_cli_config.py +++ b/tests/helpers/test_cli_config.py @@ -1,6 +1,6 @@ # SPDX-FileCopyrightText: 2019-2020 CERN. # SPDX-FileCopyrightText: 2019-2021 Northwestern University. -# SPDX-FileCopyrightText: 2025-2026-2026 KTH Royal Institute of Technology. +# SPDX-FileCopyrightText: 2025-2026 KTH Royal Institute of Technology. # SPDX-License-Identifier: MIT """Module config_file tests.""" @@ -31,7 +31,6 @@ def test_cli_config_write(): "author_name": "CERN", "author_email": "info@my-site.com", "year": "2022", - "database": "postgresql", "_template": "https://github.com/inveniosoftware/cookiecutter-invenio-rdm.git", # noqa } } @@ -63,7 +62,6 @@ def config_dir(): "author_name": "CERN", "author_email": "info@my-site.com", "year": "2022", - "database": "postgresql", "_template": "https://github.com/inveniosoftware/cookiecutter-invenio-rdm.git", # noqa } } @@ -118,8 +116,8 @@ def test_cli_config_get_project_shortname(config_dir): assert cli_config.get_project_shortname() == "my-site" -def test_javascript_package_manager_config(tmpdir): - """Test JavaScript package manager defaults to pnpm in CLI config.""" +def test_package_manager_and_service_defaults(tmpdir): + """Test package manager, database, and search defaults in CLI config.""" project_dir = tmpdir.mkdir("test-project") flavour = "RDM" replay = { @@ -132,7 +130,6 @@ def test_javascript_package_manager_config(tmpdir): "author_name": "CERN", "author_email": "info@my-site.com", "year": "2022", - "database": "postgresql", "_template": "https://github.com/inveniosoftware/cookiecutter-invenio-rdm.git", # noqa } } @@ -144,4 +141,5 @@ def test_javascript_package_manager_config(tmpdir): assert config.has_option(CLIConfig.CLI_SECTION, "javascript_package_manager") assert config.get(CLIConfig.CLI_SECTION, "javascript_package_manager") == "pnpm" + assert config.get(CLIConfig.COOKIECUTTER_SECTION, "database") == "postgresql" assert config.get(CLIConfig.COOKIECUTTER_SECTION, "search") == "opensearch2" From c19d88d9653c272b8d5392c80020e803a5c9ac97 Mon Sep 17 00:00:00 2001 From: Sam Arbid Date: Mon, 15 Jun 2026 22:18:04 +0200 Subject: [PATCH 6/6] fix: update get_db_type and get_search_type methods * Retrieve database and search types from configuration instead of returning hardcoded values. --- invenio_cli/helpers/cli_config.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/invenio_cli/helpers/cli_config.py b/invenio_cli/helpers/cli_config.py index 8a0102d..ca72236 100644 --- a/invenio_cli/helpers/cli_config.py +++ b/invenio_cli/helpers/cli_config.py @@ -166,15 +166,13 @@ def get_web_host(self): """Returns web host.""" return self.private_config[CLIConfig.CLI_SECTION].get("web_host", "127.0.0.1") - @staticmethod - def get_db_type(): + def get_db_type(self): """Returns the database type.""" - return "postgresql" + return self.config[CLIConfig.COOKIECUTTER_SECTION].get("database", "postgresql") - @staticmethod - def get_search_type(): + def get_search_type(self): """Returns the search type.""" - return "opensearch2" + return self.config[CLIConfig.COOKIECUTTER_SECTION].get("search", "opensearch2") def get_file_storage(self): """Returns the file storage (local, s3, etc.).""" @@ -223,8 +221,8 @@ def write(cls, project_dir, flavour, replay): config_parser[cls.COOKIECUTTER_SECTION][key] = str(value) # Keep compatibility with older tooling that expects `database` and `search` to exist. # Backend choice has been removed; PostgreSQL and OpenSearch2 are fixed. - config_parser[cls.COOKIECUTTER_SECTION]["database"] = cls.get_db_type() - config_parser[cls.COOKIECUTTER_SECTION]["search"] = cls.get_search_type() + config_parser[cls.COOKIECUTTER_SECTION]["database"] = "postgresql" + config_parser[cls.COOKIECUTTER_SECTION]["search"] = "opensearch2" # Generated files section config_parser[cls.FILES_SECTION] = get_created_files(project_dir)