splent-cli 1.7.0__tar.gz → 1.8.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {splent_cli-1.7.0/src/splent_cli.egg-info → splent_cli-1.8.0}/PKG-INFO +2 -1
- {splent_cli-1.7.0 → splent_cli-1.8.0}/pyproject.toml +2 -1
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/check/check_pyproject.py +53 -14
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/export/export_puml.py +100 -25
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/feature/feature_release.py +22 -9
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/product/product_containers.py +3 -3
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/services/preflight.py +50 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0/src/splent_cli.egg-info}/PKG-INFO +2 -1
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli.egg-info/requires.txt +1 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/LICENSE +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/README.md +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/setup.cfg +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/__init__.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/__main__.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/cli.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/__init__.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/cache/__init__.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/cache/cache_clear.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/cache/cache_orphans.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/cache/cache_outdated.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/cache/cache_prune.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/cache/cache_size.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/cache/cache_status.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/cache/cache_usage.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/cache/cache_versions.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/check/__init__.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/check/check_deps.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/check/check_docker.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/check/check_env.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/check/check_features.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/check/check_github.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/check/check_infra.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/check/check_product.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/check/check_pypi.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/clear/__init__.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/clear/clear_build.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/clear/clear_log.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/clear/clear_uploads.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/command/__init__.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/command/command_create.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/coverage.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/database/db_console.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/database/db_dump.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/database/db_migrate.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/database/db_reset.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/database/db_restore.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/database/db_rollback.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/database/db_seed.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/database/db_status.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/database/db_upgrade.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/doctor.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/env/env_list.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/env/env_set.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/env/env_show.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/export/__init__.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/feature/feature_add.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/feature/feature_attach.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/feature/feature_clean.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/feature/feature_clone.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/feature/feature_compat.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/feature/feature_compile.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/feature/feature_contract.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/feature/feature_create.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/feature/feature_delete.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/feature/feature_detach.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/feature/feature_discard.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/feature/feature_drift.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/feature/feature_env.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/feature/feature_fork.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/feature/feature_git.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/feature/feature_hook_add.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/feature/feature_hook_remove.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/feature/feature_hooks.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/feature/feature_impact.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/feature/feature_inject_config.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/feature/feature_install.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/feature/feature_list.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/feature/feature_order.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/feature/feature_outdated.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/feature/feature_pin.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/feature/feature_pip_install.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/feature/feature_pull.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/feature/feature_refine.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/feature/feature_remove.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/feature/feature_rename.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/feature/feature_search.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/feature/feature_status.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/feature/feature_sync_template.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/feature/feature_test.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/feature/feature_translate.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/feature/feature_unlock.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/feature/feature_upgrade.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/feature/feature_versions.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/feature/feature_xray.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/lint.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/locust.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/product/__init__.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/product/product_auto_require.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/product/product_build.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/product/product_clean.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/product/product_commands.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/product/product_config.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/product/product_configure.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/product/product_console.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/product/product_create.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/product/product_deploy.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/product/product_derive.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/product/product_deselect.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/product/product_down.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/product/product_drift.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/product/product_env.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/product/product_list.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/product/product_logs.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/product/product_missing.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/product/product_port.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/product/product_release.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/product/product_resolve.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/product/product_restart.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/product/product_routes.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/product/product_run.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/product/product_select.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/product/product_shell.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/product/product_signals.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/product/product_sync_template.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/product/product_test.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/product/product_up.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/product/product_validate.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/release/__init__.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/release/release_core.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/selenium.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/spl/__init__.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/spl/spl_add_constraints.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/spl/spl_add_feature.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/spl/spl_configurations.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/spl/spl_create.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/spl/spl_deps.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/spl/spl_features.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/spl/spl_fetch.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/spl/spl_info.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/spl/spl_list.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/spl/spl_utils.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/tokens_setup.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/uvl/uvl_utils.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/version.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/services/__init__.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/services/compose.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/services/context.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/services/release.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/utils/__init__.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/utils/cache_utils.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/utils/command_loader.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/utils/contract_freshness.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/utils/db_utils.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/utils/decorators.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/utils/dynamic_imports.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/utils/feature_installer.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/utils/feature_utils.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/utils/git_url.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/utils/integrity.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/utils/lifecycle.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/utils/manifest.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/utils/path_utils.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/utils/template_drift.py +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli.egg-info/SOURCES.txt +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli.egg-info/dependency_links.txt +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli.egg-info/entry_points.txt +0 -0
- {splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: splent_cli
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.8.0
|
|
4
4
|
Summary: SPLENT-CLI is a CLI to be able to work on your development more easily.
|
|
5
5
|
Author-email: DiversoLab <diversolab@us.es>
|
|
6
6
|
Project-URL: Homepage, https://github.com/diverso-lab/splent_cli
|
|
@@ -10,6 +10,7 @@ Description-Content-Type: text/markdown
|
|
|
10
10
|
License-File: LICENSE
|
|
11
11
|
Requires-Dist: click==8.1.8
|
|
12
12
|
Requires-Dist: packaging>=24.0
|
|
13
|
+
Requires-Dist: requests>=2.31.0
|
|
13
14
|
Provides-Extra: dev
|
|
14
15
|
Requires-Dist: setuptools==80.3.1; extra == "dev"
|
|
15
16
|
Requires-Dist: pytest==8.3.4; extra == "dev"
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "splent_cli"
|
|
7
|
-
version = "1.
|
|
7
|
+
version = "1.8.0"
|
|
8
8
|
description = "SPLENT-CLI is a CLI to be able to work on your development more easily."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.13"
|
|
@@ -14,6 +14,7 @@ license-files = ["LICENSE"]
|
|
|
14
14
|
dependencies = [
|
|
15
15
|
"click==8.1.8",
|
|
16
16
|
"packaging>=24.0",
|
|
17
|
+
"requests>=2.31.0",
|
|
17
18
|
]
|
|
18
19
|
|
|
19
20
|
[project.optional-dependencies]
|
|
@@ -9,7 +9,6 @@ import click
|
|
|
9
9
|
import tomllib
|
|
10
10
|
|
|
11
11
|
from splent_cli.services import context
|
|
12
|
-
from splent_cli.utils.feature_utils import read_features_from_data
|
|
13
12
|
|
|
14
13
|
|
|
15
14
|
def _find_missing_pkgs(deps: list) -> list:
|
|
@@ -88,29 +87,69 @@ def check_pyproject():
|
|
|
88
87
|
_ok(f"All {len(deps)} dependencies satisfied")
|
|
89
88
|
|
|
90
89
|
# Features
|
|
91
|
-
features = read_features_from_data(data)
|
|
92
|
-
_ok(f"{len(features)} features declared in [tool.splent.features]")
|
|
93
|
-
|
|
94
90
|
splent = data.get("tool", {}).get("splent", {})
|
|
91
|
+
base_feats = splent.get("features", [])
|
|
95
92
|
dev_feats = splent.get("features_dev", [])
|
|
96
93
|
prod_feats = splent.get("features_prod", [])
|
|
94
|
+
|
|
95
|
+
_ok(f"{len(base_feats)} features in [tool.splent].features")
|
|
97
96
|
if dev_feats:
|
|
98
97
|
_ok(f"{len(dev_feats)} dev-only features")
|
|
99
98
|
if prod_feats:
|
|
100
99
|
_ok(f"{len(prod_feats)} prod-only features")
|
|
101
100
|
|
|
102
|
-
#
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
101
|
+
# Check for duplicates across feature lists
|
|
102
|
+
def _bare_name(entry):
|
|
103
|
+
name = entry.split("/")[-1] if "/" in entry else entry
|
|
104
|
+
return name.split("@")[0]
|
|
105
|
+
|
|
106
|
+
all_entries = base_feats + dev_feats + prod_feats
|
|
107
|
+
seen_names = {}
|
|
108
|
+
for entry in all_entries:
|
|
109
|
+
bare = _bare_name(entry)
|
|
110
|
+
seen_names.setdefault(bare, []).append(entry)
|
|
111
|
+
|
|
112
|
+
for bare, entries in seen_names.items():
|
|
113
|
+
if len(entries) > 1:
|
|
114
|
+
short = bare.replace("splent_feature_", "")
|
|
115
|
+
_fail(f"Duplicate feature '{short}': {', '.join(entries)}")
|
|
116
|
+
|
|
117
|
+
# Check for inconsistent namespaces
|
|
118
|
+
namespaces = set()
|
|
119
|
+
for entry in all_entries:
|
|
120
|
+
if "/" in entry:
|
|
121
|
+
ns = entry.split("/")[0]
|
|
122
|
+
namespaces.add(ns)
|
|
123
|
+
if len(namespaces) > 1:
|
|
124
|
+
_warn(
|
|
125
|
+
f"Inconsistent namespaces: {', '.join(sorted(namespaces))} — use one format consistently"
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
# SPL / UVL
|
|
129
|
+
spl_name = splent.get("spl")
|
|
130
|
+
if spl_name:
|
|
131
|
+
uvl_path = os.path.join(
|
|
132
|
+
workspace, "splent_catalog", spl_name, f"{spl_name}.uvl"
|
|
133
|
+
)
|
|
134
|
+
if os.path.isfile(uvl_path):
|
|
135
|
+
_ok(f"SPL catalog: {spl_name} (UVL found)")
|
|
110
136
|
else:
|
|
111
|
-
_fail(
|
|
137
|
+
_fail(
|
|
138
|
+
f"SPL catalog: {spl_name} — UVL not found at splent_catalog/{spl_name}/{spl_name}.uvl"
|
|
139
|
+
)
|
|
112
140
|
else:
|
|
113
|
-
|
|
141
|
+
# Legacy fallback
|
|
142
|
+
uvl_cfg = splent.get("uvl", {})
|
|
143
|
+
uvl_file = uvl_cfg.get("file")
|
|
144
|
+
if uvl_file:
|
|
145
|
+
app_path = os.path.join(workspace, product)
|
|
146
|
+
uvl_path = os.path.join(app_path, "uvl", uvl_file)
|
|
147
|
+
if os.path.exists(uvl_path):
|
|
148
|
+
_ok(f"UVL file found: uvl/{uvl_file} (legacy)")
|
|
149
|
+
else:
|
|
150
|
+
_fail(f"UVL file not found: uvl/{uvl_file}")
|
|
151
|
+
else:
|
|
152
|
+
_warn("No SPL configured — set [tool.splent].spl in pyproject.toml")
|
|
114
153
|
|
|
115
154
|
click.echo()
|
|
116
155
|
if fail:
|
|
@@ -149,8 +149,8 @@ def _parse_models(models_path: str) -> list[dict]:
|
|
|
149
149
|
text = "\n".join(joined_lines)
|
|
150
150
|
|
|
151
151
|
classes = []
|
|
152
|
-
# Split by class definition
|
|
153
|
-
class_blocks = re.split(r"^(class \w
|
|
152
|
+
# Split by class definition (with or without parentheses for mixins)
|
|
153
|
+
class_blocks = re.split(r"^(class \w+(?:\(.*?\))?:)", text, flags=re.MULTILINE)
|
|
154
154
|
|
|
155
155
|
i = 1
|
|
156
156
|
while i < len(class_blocks):
|
|
@@ -158,7 +158,7 @@ def _parse_models(models_path: str) -> list[dict]:
|
|
|
158
158
|
body = class_blocks[i + 1] if i + 1 < len(class_blocks) else ""
|
|
159
159
|
i += 2
|
|
160
160
|
|
|
161
|
-
class_m = re.match(r"class (\w+)
|
|
161
|
+
class_m = re.match(r"class (\w+)", header)
|
|
162
162
|
if not class_m:
|
|
163
163
|
continue
|
|
164
164
|
class_name = class_m.group(1)
|
|
@@ -213,8 +213,11 @@ def _parse_models(models_path: str) -> list[dict]:
|
|
|
213
213
|
if rel_m:
|
|
214
214
|
rel_name = rel_m.group(1)
|
|
215
215
|
rel_args = rel_m.group(2)
|
|
216
|
-
|
|
217
|
-
|
|
216
|
+
# Target can be unquoted (User) or quoted ("User" / 'User')
|
|
217
|
+
target_m = re.match(r"""[\"']?(\w+)[\"']?""", rel_args)
|
|
218
|
+
target = target_m.group(1) if target_m else None
|
|
219
|
+
if not target:
|
|
220
|
+
continue
|
|
218
221
|
uselist = "uselist=False" not in rel_args
|
|
219
222
|
relationships.append(
|
|
220
223
|
{
|
|
@@ -668,11 +671,16 @@ def _render_exports(
|
|
|
668
671
|
)
|
|
669
672
|
except subprocess.CalledProcessError as e:
|
|
670
673
|
click.secho("❌ PlantUML failed to render diagram.", fg="red")
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
click.secho(stderr
|
|
674
|
+
stderr = e.stderr
|
|
675
|
+
if isinstance(stderr, bytes):
|
|
676
|
+
stderr = stderr.decode(errors="replace")
|
|
677
|
+
if stderr:
|
|
678
|
+
click.secho(stderr.strip(), fg="bright_black")
|
|
679
|
+
stdout = e.stdout
|
|
680
|
+
if isinstance(stdout, bytes):
|
|
681
|
+
stdout = stdout.decode(errors="replace")
|
|
682
|
+
if stdout:
|
|
683
|
+
click.secho(stdout.strip(), fg="bright_black")
|
|
676
684
|
return
|
|
677
685
|
|
|
678
686
|
try:
|
|
@@ -780,21 +788,41 @@ def export_puml(
|
|
|
780
788
|
product = context.require_app()
|
|
781
789
|
product_dir = os.path.join(workspace, product)
|
|
782
790
|
|
|
783
|
-
# Read UVL
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
791
|
+
# Read UVL — try SPL catalog first, fall back to legacy [tool.splent.uvl]
|
|
792
|
+
import tomllib
|
|
793
|
+
|
|
794
|
+
uvl_path = None
|
|
795
|
+
pyproject_path = os.path.join(product_dir, "pyproject.toml")
|
|
796
|
+
if os.path.isfile(pyproject_path):
|
|
797
|
+
with open(pyproject_path, "rb") as f:
|
|
798
|
+
pydata = tomllib.load(f)
|
|
799
|
+
spl_name = pydata.get("tool", {}).get("splent", {}).get("spl")
|
|
800
|
+
if spl_name:
|
|
801
|
+
candidate = os.path.join(
|
|
802
|
+
workspace, "splent_catalog", spl_name, f"{spl_name}.uvl"
|
|
803
|
+
)
|
|
804
|
+
if os.path.isfile(candidate):
|
|
805
|
+
uvl_path = candidate
|
|
806
|
+
|
|
807
|
+
# Legacy fallback: [tool.splent.uvl].file
|
|
808
|
+
if not uvl_path:
|
|
809
|
+
try:
|
|
810
|
+
uvl_cfg = PyprojectReader.for_product(product_dir).uvl_config
|
|
811
|
+
uvl_file = uvl_cfg.get("file")
|
|
812
|
+
if uvl_file:
|
|
813
|
+
candidate = os.path.join(product_dir, "uvl", uvl_file)
|
|
814
|
+
if os.path.isfile(candidate):
|
|
815
|
+
uvl_path = candidate
|
|
816
|
+
except (FileNotFoundError, RuntimeError):
|
|
817
|
+
pass
|
|
818
|
+
|
|
819
|
+
if not uvl_path:
|
|
820
|
+
click.secho(
|
|
821
|
+
"❌ No UVL file found.\n"
|
|
822
|
+
" Set [tool.splent].spl in pyproject.toml (SPL catalog)\n"
|
|
823
|
+
" or [tool.splent.uvl].file (legacy).",
|
|
824
|
+
fg="red",
|
|
825
|
+
)
|
|
798
826
|
raise SystemExit(1)
|
|
799
827
|
|
|
800
828
|
click.echo(f"📖 Reading UVL model: {uvl_path}")
|
|
@@ -848,6 +876,53 @@ def export_puml(
|
|
|
848
876
|
if parsed:
|
|
849
877
|
all_models[package] = parsed
|
|
850
878
|
break
|
|
879
|
+
# Apply refinement mixins: merge mixin attributes into target models
|
|
880
|
+
for package, fpath in feature_paths.items():
|
|
881
|
+
pyproject_path = os.path.join(fpath, "pyproject.toml")
|
|
882
|
+
if not os.path.isfile(pyproject_path):
|
|
883
|
+
continue
|
|
884
|
+
import tomllib as _tomllib
|
|
885
|
+
|
|
886
|
+
with open(pyproject_path, "rb") as f:
|
|
887
|
+
feat_data = _tomllib.load(f)
|
|
888
|
+
extends = (
|
|
889
|
+
feat_data.get("tool", {})
|
|
890
|
+
.get("splent", {})
|
|
891
|
+
.get("refinement", {})
|
|
892
|
+
.get("extends", {})
|
|
893
|
+
.get("models", [])
|
|
894
|
+
)
|
|
895
|
+
if not extends:
|
|
896
|
+
continue
|
|
897
|
+
# Parse the mixin's models.py
|
|
898
|
+
mixin_models = []
|
|
899
|
+
src_root = os.path.join(fpath, "src")
|
|
900
|
+
if os.path.isdir(src_root):
|
|
901
|
+
for org_dir in os.listdir(src_root):
|
|
902
|
+
mpath = os.path.join(src_root, org_dir, package, "models.py")
|
|
903
|
+
if os.path.isfile(mpath):
|
|
904
|
+
mixin_models = _parse_models(mpath)
|
|
905
|
+
break
|
|
906
|
+
# Merge each mixin into its target model
|
|
907
|
+
for ext in extends:
|
|
908
|
+
target_name = ext.get("target")
|
|
909
|
+
mixin_name = ext.get("mixin")
|
|
910
|
+
if not target_name or not mixin_name:
|
|
911
|
+
continue
|
|
912
|
+
# Find the mixin class in parsed mixin_models
|
|
913
|
+
mixin_cls = next(
|
|
914
|
+
(m for m in mixin_models if m["name"] == mixin_name), None
|
|
915
|
+
)
|
|
916
|
+
if not mixin_cls:
|
|
917
|
+
continue
|
|
918
|
+
# Find the target model across all parsed features
|
|
919
|
+
for feat_models in all_models.values():
|
|
920
|
+
for model in feat_models:
|
|
921
|
+
if model["name"] == target_name:
|
|
922
|
+
model["attributes"].extend(mixin_cls["attributes"])
|
|
923
|
+
model["methods"].extend(mixin_cls["methods"])
|
|
924
|
+
break
|
|
925
|
+
|
|
851
926
|
click.echo(
|
|
852
927
|
f"📋 Parsed models from {len(all_models)}/{len(feature_paths)} features."
|
|
853
928
|
)
|
|
@@ -273,14 +273,24 @@ def _scan_dependencies(
|
|
|
273
273
|
if f"splent_feature_{short_name}" != own_feature_name:
|
|
274
274
|
required_features.add(short_name)
|
|
275
275
|
|
|
276
|
-
for
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
276
|
+
for line in text.splitlines():
|
|
277
|
+
stripped = line.lstrip()
|
|
278
|
+
# Skip comments and docstrings
|
|
279
|
+
if (
|
|
280
|
+
stripped.startswith("#")
|
|
281
|
+
or stripped.startswith('"""')
|
|
282
|
+
or stripped.startswith("'''")
|
|
283
|
+
):
|
|
284
|
+
continue
|
|
285
|
+
for var in re.findall(
|
|
286
|
+
r"""os\.(?:getenv|environ\.get)\s*\(\s*['"]([A-Z][A-Z0-9_]+)['"]""",
|
|
287
|
+
stripped,
|
|
288
|
+
):
|
|
289
|
+
env_vars.add(var)
|
|
290
|
+
for var in re.findall(
|
|
291
|
+
r"""os\.environ\s*\[\s*['"]([A-Z][A-Z0-9_]+)['"]""", stripped
|
|
292
|
+
):
|
|
293
|
+
env_vars.add(var)
|
|
284
294
|
|
|
285
295
|
return sorted(required_features), sorted(env_vars)
|
|
286
296
|
|
|
@@ -330,12 +340,14 @@ def write_contract(pyproject_path: str, contract: dict, feature_name: str) -> No
|
|
|
330
340
|
text = path.read_text()
|
|
331
341
|
|
|
332
342
|
existing_description = f"{feature_name} feature"
|
|
343
|
+
existing_env = None
|
|
333
344
|
try:
|
|
334
345
|
data = tomllib.loads(text)
|
|
335
346
|
splent_contract = data.get("tool", {}).get("splent", {}).get("contract", {})
|
|
336
347
|
desc = splent_contract.get("description")
|
|
337
348
|
if desc:
|
|
338
349
|
existing_description = desc
|
|
350
|
+
existing_env = splent_contract.get("env")
|
|
339
351
|
except Exception:
|
|
340
352
|
pass
|
|
341
353
|
|
|
@@ -373,7 +385,8 @@ def write_contract(pyproject_path: str, contract: dict, feature_name: str) -> No
|
|
|
373
385
|
"# Do not edit manually — re-run `splent feature:contract --write` to refresh.\n"
|
|
374
386
|
"[tool.splent.contract]\n"
|
|
375
387
|
f'description = "{existing_description}"\n'
|
|
376
|
-
"\n"
|
|
388
|
+
+ (f'env = "{existing_env}"\n' if existing_env else "")
|
|
389
|
+
+ "\n"
|
|
377
390
|
"[tool.splent.contract.provides]\n"
|
|
378
391
|
f"routes = {_toml_list(contract['routes'])}\n"
|
|
379
392
|
f"blueprints = {_toml_list(contract['blueprints'])}\n"
|
|
@@ -235,10 +235,10 @@ def product_docker(env_dev, env_prod):
|
|
|
235
235
|
seen.add(key)
|
|
236
236
|
unique.append((label, port, kind))
|
|
237
237
|
|
|
238
|
-
http_services = [(
|
|
239
|
-
tcp_services = [(
|
|
238
|
+
http_services = [(lbl, p) for lbl, p, k in unique if k == "http"]
|
|
239
|
+
tcp_services = [(lbl, p) for lbl, p, k in unique if k == "tcp"]
|
|
240
240
|
all_services = http_services + tcp_services
|
|
241
|
-
label_width = max((len(
|
|
241
|
+
label_width = max((len(lbl) for lbl, _ in all_services), default=20) + 2
|
|
242
242
|
|
|
243
243
|
if http_services:
|
|
244
244
|
click.secho(" Accessible services:", bold=True)
|
|
@@ -106,6 +106,56 @@ def run_preflight(*, interactive: bool = True, build_mode: bool = False) -> bool
|
|
|
106
106
|
|
|
107
107
|
failed = False
|
|
108
108
|
|
|
109
|
+
# Phase 0: pyproject sanity (duplicates, namespaces, SPL)
|
|
110
|
+
splent_cfg = data.get("tool", {}).get("splent", {})
|
|
111
|
+
base_feats = splent_cfg.get("features", [])
|
|
112
|
+
dev_feats = splent_cfg.get("features_dev", [])
|
|
113
|
+
prod_feats = splent_cfg.get("features_prod", [])
|
|
114
|
+
|
|
115
|
+
all_entries = base_feats + dev_feats + prod_feats
|
|
116
|
+
seen = {}
|
|
117
|
+
for entry in all_entries:
|
|
118
|
+
bare = (
|
|
119
|
+
entry.split("/")[-1].split("@")[0] if "/" in entry else entry.split("@")[0]
|
|
120
|
+
)
|
|
121
|
+
seen.setdefault(bare, []).append(entry)
|
|
122
|
+
|
|
123
|
+
duplicates = {k: v for k, v in seen.items() if len(v) > 1}
|
|
124
|
+
if duplicates:
|
|
125
|
+
if interactive:
|
|
126
|
+
for bare, entries in duplicates.items():
|
|
127
|
+
short = bare.replace("splent_feature_", "")
|
|
128
|
+
click.secho(
|
|
129
|
+
f" pyproject duplicate '{short}': {', '.join(entries)}", fg="red"
|
|
130
|
+
)
|
|
131
|
+
failed = True
|
|
132
|
+
else:
|
|
133
|
+
namespaces = set()
|
|
134
|
+
for entry in all_entries:
|
|
135
|
+
if "/" in entry:
|
|
136
|
+
namespaces.add(entry.split("/")[0])
|
|
137
|
+
if len(namespaces) > 1:
|
|
138
|
+
if interactive:
|
|
139
|
+
click.secho(
|
|
140
|
+
f" pyproject inconsistent namespaces: {', '.join(sorted(namespaces))}",
|
|
141
|
+
fg="yellow",
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
spl_name = splent_cfg.get("spl")
|
|
145
|
+
if spl_name:
|
|
146
|
+
uvl_check = os.path.join(
|
|
147
|
+
workspace, "splent_catalog", spl_name, f"{spl_name}.uvl"
|
|
148
|
+
)
|
|
149
|
+
if not os.path.isfile(uvl_check):
|
|
150
|
+
if interactive:
|
|
151
|
+
click.secho(
|
|
152
|
+
f" pyproject SPL '{spl_name}' — UVL not found in catalog", fg="red"
|
|
153
|
+
)
|
|
154
|
+
failed = True
|
|
155
|
+
|
|
156
|
+
if failed:
|
|
157
|
+
return False
|
|
158
|
+
|
|
109
159
|
# Phase 1: SAT
|
|
110
160
|
try:
|
|
111
161
|
sat_ok, selected, _, _ = _run_sat_check(workspace, app_name, data, None, False)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: splent_cli
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.8.0
|
|
4
4
|
Summary: SPLENT-CLI is a CLI to be able to work on your development more easily.
|
|
5
5
|
Author-email: DiversoLab <diversolab@us.es>
|
|
6
6
|
Project-URL: Homepage, https://github.com/diverso-lab/splent_cli
|
|
@@ -10,6 +10,7 @@ Description-Content-Type: text/markdown
|
|
|
10
10
|
License-File: LICENSE
|
|
11
11
|
Requires-Dist: click==8.1.8
|
|
12
12
|
Requires-Dist: packaging>=24.0
|
|
13
|
+
Requires-Dist: requests>=2.31.0
|
|
13
14
|
Provides-Extra: dev
|
|
14
15
|
Requires-Dist: setuptools==80.3.1; extra == "dev"
|
|
15
16
|
Requires-Dist: pytest==8.3.4; extra == "dev"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/feature/feature_hook_remove.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/feature/feature_inject_config.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/feature/feature_pip_install.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/feature/feature_sync_template.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/product/product_auto_require.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{splent_cli-1.7.0 → splent_cli-1.8.0}/src/splent_cli/commands/product/product_sync_template.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|