splent-cli 1.12.0__tar.gz → 1.16.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.12.0/src/splent_cli.egg-info → splent_cli-1.16.0}/PKG-INFO +2 -1
- {splent_cli-1.12.0 → splent_cli-1.16.0}/pyproject.toml +2 -1
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/cli.py +14 -2
- splent_cli-1.16.0/src/splent_cli/commands/check/check_contracts.py +212 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/check/check_deps.py +13 -8
- splent_cli-1.16.0/src/splent_cli/commands/check/check_pypi.py +127 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/check/check_pyproject.py +15 -5
- splent_cli-1.16.0/src/splent_cli/commands/check/check_releases.py +394 -0
- splent_cli-1.16.0/src/splent_cli/commands/database/db_dump.py +188 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/database/db_reset.py +24 -10
- splent_cli-1.16.0/src/splent_cli/commands/database/db_restore.py +171 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/database/db_rollback.py +4 -9
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/database/db_seed.py +5 -8
- splent_cli-1.16.0/src/splent_cli/commands/database/db_upgrade.py +229 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/export/export_puml.py +3 -5
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/feature/feature_add.py +38 -15
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/feature/feature_attach.py +60 -24
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/feature/feature_clean.py +5 -35
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/feature/feature_clone.py +2 -35
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/feature/feature_contract.py +53 -1
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/feature/feature_detach.py +13 -8
- splent_cli-1.16.0/src/splent_cli/commands/feature/feature_info.py +213 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/feature/feature_install.py +5 -24
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/feature/feature_order.py +7 -9
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/feature/feature_outdated.py +5 -28
- splent_cli-1.16.0/src/splent_cli/commands/feature/feature_pip_install.py +265 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/feature/feature_release.py +308 -9
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/feature/feature_remove.py +61 -29
- splent_cli-1.16.0/src/splent_cli/commands/feature/feature_search.py +239 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/feature/feature_upgrade.py +9 -32
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/feature/feature_versions.py +13 -83
- splent_cli-1.16.0/src/splent_cli/commands/locust.py +140 -0
- splent_cli-1.16.0/src/splent_cli/commands/marketplace/login.py +164 -0
- splent_cli-1.16.0/src/splent_cli/commands/marketplace/logout.py +101 -0
- splent_cli-1.16.0/src/splent_cli/commands/marketplace/marketplace_auth_utils.py +298 -0
- splent_cli-1.16.0/src/splent_cli/commands/marketplace/marketplace_index.py +194 -0
- splent_cli-1.16.0/src/splent_cli/commands/marketplace/whoami.py +140 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/product/product_build.py +90 -14
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/product/product_configure.py +13 -6
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/product/product_create.py +61 -57
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/product/product_deploy.py +119 -18
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/product/product_port.py +35 -6
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/product/product_release.py +66 -7
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/product/product_up.py +10 -2
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/product/product_validate.py +40 -8
- splent_cli-1.16.0/src/splent_cli/commands/release/release_core.py +129 -0
- splent_cli-1.16.0/src/splent_cli/commands/release/release_resume.py +399 -0
- splent_cli-1.16.0/src/splent_cli/commands/spl/spl_create.py +52 -0
- splent_cli-1.16.0/src/splent_cli/commands/spl/spl_fetch.py +41 -0
- splent_cli-1.16.0/src/splent_cli/commands/spl/spl_info.py +93 -0
- splent_cli-1.16.0/src/splent_cli/commands/spl/spl_list.py +68 -0
- splent_cli-1.16.0/src/splent_cli/commands/spl/spl_migrate_catalog.py +180 -0
- splent_cli-1.16.0/src/splent_cli/commands/spl/spl_outdated.py +185 -0
- splent_cli-1.16.0/src/splent_cli/commands/spl/spl_pin.py +89 -0
- splent_cli-1.16.0/src/splent_cli/commands/spl/spl_publish.py +402 -0
- splent_cli-1.16.0/src/splent_cli/commands/spl/spl_utils.py +91 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/uvl/uvl_utils.py +22 -8
- splent_cli-1.16.0/src/splent_cli/services/credentials.py +355 -0
- splent_cli-1.16.0/src/splent_cli/services/index_refresh.py +95 -0
- splent_cli-1.16.0/src/splent_cli/services/marketplace.py +560 -0
- splent_cli-1.16.0/src/splent_cli/services/marketplace_api.py +635 -0
- splent_cli-1.16.0/src/splent_cli/services/marketplace_url.py +149 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/services/preflight.py +24 -6
- splent_cli-1.16.0/src/splent_cli/services/registry.py +666 -0
- splent_cli-1.16.0/src/splent_cli/services/release.py +1292 -0
- splent_cli-1.16.0/src/splent_cli/services/release_gate.py +1025 -0
- splent_cli-1.16.0/src/splent_cli/services/spl_store.py +760 -0
- splent_cli-1.16.0/src/splent_cli/utils/archetype.py +56 -0
- splent_cli-1.16.0/src/splent_cli/utils/command_loader.py +112 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/utils/dynamic_imports.py +10 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/utils/feature_utils.py +126 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/utils/git_url.py +52 -8
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/utils/template_drift.py +6 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0/src/splent_cli.egg-info}/PKG-INFO +2 -1
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli.egg-info/SOURCES.txt +22 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli.egg-info/requires.txt +1 -0
- splent_cli-1.12.0/src/splent_cli/commands/check/check_pypi.py +0 -118
- splent_cli-1.12.0/src/splent_cli/commands/database/db_dump.py +0 -86
- splent_cli-1.12.0/src/splent_cli/commands/database/db_restore.py +0 -117
- splent_cli-1.12.0/src/splent_cli/commands/database/db_upgrade.py +0 -104
- splent_cli-1.12.0/src/splent_cli/commands/feature/feature_pip_install.py +0 -100
- splent_cli-1.12.0/src/splent_cli/commands/feature/feature_search.py +0 -144
- splent_cli-1.12.0/src/splent_cli/commands/locust.py +0 -271
- splent_cli-1.12.0/src/splent_cli/commands/release/release_core.py +0 -68
- splent_cli-1.12.0/src/splent_cli/commands/spl/spl_create.py +0 -48
- splent_cli-1.12.0/src/splent_cli/commands/spl/spl_fetch.py +0 -36
- splent_cli-1.12.0/src/splent_cli/commands/spl/spl_info.py +0 -66
- splent_cli-1.12.0/src/splent_cli/commands/spl/spl_list.py +0 -59
- splent_cli-1.12.0/src/splent_cli/commands/spl/spl_utils.py +0 -89
- splent_cli-1.12.0/src/splent_cli/services/release.py +0 -614
- splent_cli-1.12.0/src/splent_cli/utils/command_loader.py +0 -42
- {splent_cli-1.12.0 → splent_cli-1.16.0}/LICENSE +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/README.md +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/setup.cfg +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/__init__.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/__main__.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/__init__.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/cache/__init__.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/cache/cache_clear.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/cache/cache_orphans.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/cache/cache_outdated.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/cache/cache_prune.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/cache/cache_size.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/cache/cache_status.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/cache/cache_usage.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/cache/cache_versions.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/check/__init__.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/check/check_docker.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/check/check_env.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/check/check_features.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/check/check_github.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/check/check_infra.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/check/check_product.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/clear/__init__.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/clear/clear_build.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/clear/clear_log.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/clear/clear_uploads.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/command/__init__.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/command/command_create.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/coverage.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/database/db_console.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/database/db_migrate.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/database/db_status.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/doctor.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/env/env_list.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/env/env_set.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/env/env_show.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/export/__init__.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/feature/feature_compat.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/feature/feature_compile.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/feature/feature_create.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/feature/feature_delete.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/feature/feature_discard.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/feature/feature_drift.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/feature/feature_env.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/feature/feature_fork.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/feature/feature_git.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/feature/feature_hook_add.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/feature/feature_hook_remove.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/feature/feature_hooks.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/feature/feature_impact.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/feature/feature_inject_config.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/feature/feature_list.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/feature/feature_pin.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/feature/feature_pull.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/feature/feature_refine.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/feature/feature_rename.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/feature/feature_status.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/feature/feature_sync_template.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/feature/feature_test.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/feature/feature_translate.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/feature/feature_unlock.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/feature/feature_xray.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/lint.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/product/__init__.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/product/product_auto_require.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/product/product_clean.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/product/product_commands.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/product/product_config.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/product/product_console.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/product/product_containers.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/product/product_derive.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/product/product_deselect.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/product/product_down.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/product/product_drift.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/product/product_env.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/product/product_list.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/product/product_logs.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/product/product_missing.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/product/product_resolve.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/product/product_restart.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/product/product_routes.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/product/product_run.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/product/product_select.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/product/product_shell.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/product/product_signals.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/product/product_sync_template.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/product/product_test.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/release/__init__.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/selenium.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/spl/__init__.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/spl/spl_add_constraints.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/spl/spl_add_feature.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/spl/spl_compare.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/spl/spl_configurations.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/spl/spl_deps.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/spl/spl_features.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/tokens_setup.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/commands/version.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/services/__init__.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/services/compose.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/services/context.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/utils/__init__.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/utils/cache_utils.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/utils/contract_freshness.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/utils/db_utils.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/utils/decorators.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/utils/feature_installer.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/utils/integrity.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/utils/io_utils.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/utils/lifecycle.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/utils/manifest.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/utils/path_utils.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli/utils/proc.py +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli.egg-info/dependency_links.txt +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.0}/src/splent_cli.egg-info/entry_points.txt +0 -0
- {splent_cli-1.12.0 → splent_cli-1.16.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.16.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: pyyaml>=6.0
|
|
13
14
|
Requires-Dist: requests>=2.31.0
|
|
14
15
|
Requires-Dist: tomli_w>=1.0.0
|
|
15
16
|
Provides-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.16.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
|
+
"pyyaml>=6.0",
|
|
17
18
|
"requests>=2.31.0",
|
|
18
19
|
"tomli_w>=1.0.0",
|
|
19
20
|
]
|
|
@@ -3,9 +3,7 @@ import os
|
|
|
3
3
|
import click
|
|
4
4
|
from dotenv import load_dotenv
|
|
5
5
|
|
|
6
|
-
from splent_cli.utils.dynamic_imports import get_app
|
|
7
6
|
from splent_cli.utils.command_loader import load_commands
|
|
8
|
-
from splent_cli.utils.db_utils import check_db_connection
|
|
9
7
|
|
|
10
8
|
load_dotenv()
|
|
11
9
|
|
|
@@ -40,6 +38,8 @@ class SPLENTCLI(click.Group):
|
|
|
40
38
|
|
|
41
39
|
self._feature_cmds_cache: dict[str, click.BaseCommand] = {}
|
|
42
40
|
try:
|
|
41
|
+
from splent_cli.utils.dynamic_imports import get_app
|
|
42
|
+
|
|
43
43
|
app = get_app()
|
|
44
44
|
with app.app_context():
|
|
45
45
|
registry = app.extensions.get("splent_feature_commands", {})
|
|
@@ -84,6 +84,9 @@ class SPLENTCLI(click.Group):
|
|
|
84
84
|
command = self.get_command(ctx, cmd_name)
|
|
85
85
|
|
|
86
86
|
if command and getattr(command, "requires_app", False):
|
|
87
|
+
from splent_cli.utils.dynamic_imports import get_app
|
|
88
|
+
from splent_cli.utils.db_utils import check_db_connection
|
|
89
|
+
|
|
87
90
|
app = get_app()
|
|
88
91
|
if getattr(command, "requires_db", False):
|
|
89
92
|
if not check_db_connection(app):
|
|
@@ -109,6 +112,15 @@ class SPLENTCLI(click.Group):
|
|
|
109
112
|
"🧬 SPL & Variability": [
|
|
110
113
|
cmd for cmd in all_cmds if cmd.startswith(("spl:", "uvl:"))
|
|
111
114
|
],
|
|
115
|
+
"🛒 Marketplace": [
|
|
116
|
+
cmd
|
|
117
|
+
for cmd in all_cmds
|
|
118
|
+
# login/logout/whoami are bare on purpose (docker-login
|
|
119
|
+
# ergonomics), so they are listed by name next to the
|
|
120
|
+
# namespaced marketplace commands they belong with.
|
|
121
|
+
if cmd.startswith("marketplace:")
|
|
122
|
+
or cmd in ("login", "logout", "whoami")
|
|
123
|
+
],
|
|
112
124
|
"🧱 Database": [cmd for cmd in all_cmds if cmd.startswith("db:")],
|
|
113
125
|
"💾 Cache": [cmd for cmd in all_cmds if cmd.startswith("cache:")],
|
|
114
126
|
"🔍 Checks": [cmd for cmd in all_cmds if cmd.startswith("check:")],
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
"""
|
|
2
|
+
check:contracts — Verify that feature contracts and SPL UVL models agree.
|
|
3
|
+
|
|
4
|
+
The dependency truth must not be split: a feature's requires.features (in
|
|
5
|
+
[tool.splent.contract]) and the SPL's UVL implications (A => B) describe
|
|
6
|
+
the same reality from two sides. This check reports:
|
|
7
|
+
|
|
8
|
+
- contract dependencies with no matching UVL constraint (ERROR: the SPL
|
|
9
|
+
would let a product select A without B and break at runtime), and
|
|
10
|
+
- UVL implications not backed by any contract (WARNING: the dependency
|
|
11
|
+
is invisible to feature:install and the marketplace).
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
|
|
16
|
+
import click
|
|
17
|
+
import tomllib
|
|
18
|
+
|
|
19
|
+
from splent_cli.services import context, marketplace, spl_store
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _snapshot_version_key(pyproject_path: Path) -> tuple:
|
|
23
|
+
"""Semver sort key for a cache snapshot dir like splent_feature_x@v1.10.0."""
|
|
24
|
+
import re
|
|
25
|
+
|
|
26
|
+
_, _, version = pyproject_path.parent.name.partition("@")
|
|
27
|
+
m = re.match(r"v?(\d+)\.(\d+)\.(\d+)", version)
|
|
28
|
+
if not m:
|
|
29
|
+
return (-1, -1, -1)
|
|
30
|
+
return (int(m.group(1)), int(m.group(2)), int(m.group(3)))
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _local_contract_requires(workspace: str, package: str) -> list[str] | None:
|
|
34
|
+
"""requires.features of a feature found locally (workspace root, else the
|
|
35
|
+
newest cache snapshot by semver). None when not available locally."""
|
|
36
|
+
candidates = [Path(workspace) / package / "pyproject.toml"]
|
|
37
|
+
cache = Path(workspace) / ".splent_cache" / "features"
|
|
38
|
+
if cache.is_dir():
|
|
39
|
+
candidates.extend(
|
|
40
|
+
sorted(
|
|
41
|
+
cache.glob(f"*/{package}@*/pyproject.toml"),
|
|
42
|
+
key=_snapshot_version_key,
|
|
43
|
+
reverse=True,
|
|
44
|
+
)
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
for path in candidates:
|
|
48
|
+
if not path.is_file():
|
|
49
|
+
continue
|
|
50
|
+
try:
|
|
51
|
+
data = tomllib.loads(path.read_text())
|
|
52
|
+
except (OSError, tomllib.TOMLDecodeError):
|
|
53
|
+
continue
|
|
54
|
+
requires = (
|
|
55
|
+
data.get("tool", {})
|
|
56
|
+
.get("splent", {})
|
|
57
|
+
.get("contract", {})
|
|
58
|
+
.get("requires", {})
|
|
59
|
+
)
|
|
60
|
+
return {
|
|
61
|
+
"features": requires.get("features", []),
|
|
62
|
+
"optional": requires.get("features_optional", []),
|
|
63
|
+
}
|
|
64
|
+
return None
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
@click.command(
|
|
68
|
+
"check:contracts",
|
|
69
|
+
short_help="Check that feature contracts and SPL UVL constraints agree.",
|
|
70
|
+
)
|
|
71
|
+
@click.option("--spl", "spl_name", default=None, help="Check a single SPL.")
|
|
72
|
+
def check_contracts(spl_name):
|
|
73
|
+
"""
|
|
74
|
+
Cross-check requires.features in every contract against the UVL
|
|
75
|
+
constraints of every SPL model this workspace knows.
|
|
76
|
+
|
|
77
|
+
\b
|
|
78
|
+
Examples:
|
|
79
|
+
splent check:contracts
|
|
80
|
+
splent check:contracts --spl cms_spl
|
|
81
|
+
"""
|
|
82
|
+
workspace = str(context.workspace())
|
|
83
|
+
|
|
84
|
+
if spl_name:
|
|
85
|
+
spl_names = [spl_name]
|
|
86
|
+
else:
|
|
87
|
+
spl_names = spl_store.known_spls(workspace)
|
|
88
|
+
|
|
89
|
+
if not spl_names:
|
|
90
|
+
click.secho(" No SPL models known to this workspace.", fg="red")
|
|
91
|
+
click.echo(" Start one with: splent spl:create <name>")
|
|
92
|
+
raise SystemExit(1)
|
|
93
|
+
|
|
94
|
+
total_errors = 0
|
|
95
|
+
total_warnings = 0
|
|
96
|
+
|
|
97
|
+
for name in spl_names:
|
|
98
|
+
spl_errors = 0
|
|
99
|
+
spl_warnings = 0
|
|
100
|
+
pin = spl_store.read_pin(workspace, name)
|
|
101
|
+
uvl_path_str = spl_store.find_uvl(
|
|
102
|
+
workspace, name, version=pin.version, doi=pin.doi
|
|
103
|
+
)
|
|
104
|
+
click.echo()
|
|
105
|
+
click.echo(click.style(f" check:contracts {name}", bold=True))
|
|
106
|
+
click.echo(click.style(f" {'-' * 60}", fg="bright_black"))
|
|
107
|
+
|
|
108
|
+
if not uvl_path_str:
|
|
109
|
+
if pin.fetchable:
|
|
110
|
+
click.secho(
|
|
111
|
+
f" UVL not on disk, run: splent spl:fetch {name}",
|
|
112
|
+
fg="yellow",
|
|
113
|
+
)
|
|
114
|
+
else:
|
|
115
|
+
click.secho(
|
|
116
|
+
f" No UVL and no DOI for '{name}', nothing to check against.",
|
|
117
|
+
fg="yellow",
|
|
118
|
+
)
|
|
119
|
+
total_warnings += 1
|
|
120
|
+
continue
|
|
121
|
+
|
|
122
|
+
uvl_path = Path(uvl_path_str)
|
|
123
|
+
model = marketplace.parse_uvl_structure(uvl_path.read_text())
|
|
124
|
+
shorts = model["features"] # short -> {package, org, ...}
|
|
125
|
+
implications = {(a, b) for a, b in model["constraints"]}
|
|
126
|
+
|
|
127
|
+
contracts: dict[str, list[str] | None] = {}
|
|
128
|
+
for short, meta in shorts.items():
|
|
129
|
+
contracts[short] = _local_contract_requires(workspace, meta["package"])
|
|
130
|
+
|
|
131
|
+
missing_local = sorted(s for s, req in contracts.items() if req is None)
|
|
132
|
+
|
|
133
|
+
# 1. Contract deps that the UVL does not enforce.
|
|
134
|
+
for short, req in sorted(contracts.items()):
|
|
135
|
+
for dep in (req or {}).get("features", []):
|
|
136
|
+
if dep not in shorts:
|
|
137
|
+
# Dependency on a feature outside this SPL: the SPL simply
|
|
138
|
+
# cannot offer this feature safely without it.
|
|
139
|
+
click.secho(
|
|
140
|
+
f" ✗ {short} requires '{dep}' (contract), but '{dep}' "
|
|
141
|
+
f"is not a feature of {name}",
|
|
142
|
+
fg="red",
|
|
143
|
+
)
|
|
144
|
+
spl_errors += 1
|
|
145
|
+
elif (short, dep) not in implications:
|
|
146
|
+
click.secho(
|
|
147
|
+
f" ✗ {short} requires '{dep}' (contract), but the UVL "
|
|
148
|
+
f"has no '{short} => {dep}' constraint",
|
|
149
|
+
fg="red",
|
|
150
|
+
)
|
|
151
|
+
click.echo(
|
|
152
|
+
click.style(
|
|
153
|
+
f" fix: add '{short} => {dep}' to the UVL "
|
|
154
|
+
f"constraints (splent spl:add-constraints "
|
|
155
|
+
f"{name} is interactive)",
|
|
156
|
+
fg="bright_black",
|
|
157
|
+
)
|
|
158
|
+
)
|
|
159
|
+
spl_errors += 1
|
|
160
|
+
|
|
161
|
+
# 2. UVL implications with no contract behind them.
|
|
162
|
+
for a, b in sorted(implications):
|
|
163
|
+
req = contracts.get(a)
|
|
164
|
+
if a not in shorts or b not in shorts:
|
|
165
|
+
continue # constraint over infra features (redis, nginx…)
|
|
166
|
+
if req is None:
|
|
167
|
+
continue # feature not local — cannot verify
|
|
168
|
+
if b in req["optional"]:
|
|
169
|
+
continue # SPL hardening a soft (graceful) dependency — fine
|
|
170
|
+
if b not in req["features"]:
|
|
171
|
+
click.secho(
|
|
172
|
+
f" ⚠ UVL says '{a} => {b}' but {a}'s contract does not "
|
|
173
|
+
f"require '{b}'",
|
|
174
|
+
fg="yellow",
|
|
175
|
+
)
|
|
176
|
+
click.echo(
|
|
177
|
+
click.style(
|
|
178
|
+
f' fix: add "{b}" to requires.features_manual in '
|
|
179
|
+
f"{shorts[a]['package']}/pyproject.toml (preserved on "
|
|
180
|
+
"regeneration), or confirm it is SPL-level policy",
|
|
181
|
+
fg="bright_black",
|
|
182
|
+
)
|
|
183
|
+
)
|
|
184
|
+
spl_warnings += 1
|
|
185
|
+
|
|
186
|
+
if missing_local:
|
|
187
|
+
click.echo(
|
|
188
|
+
click.style(
|
|
189
|
+
f" ℹ not local (skipped): {', '.join(missing_local)}",
|
|
190
|
+
fg="bright_black",
|
|
191
|
+
)
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
if not spl_errors and not spl_warnings:
|
|
195
|
+
click.secho(" ✅ Contracts and UVL agree.", fg="green")
|
|
196
|
+
total_errors += spl_errors
|
|
197
|
+
total_warnings += spl_warnings
|
|
198
|
+
|
|
199
|
+
click.echo()
|
|
200
|
+
if total_errors or total_warnings:
|
|
201
|
+
click.echo(
|
|
202
|
+
click.style(
|
|
203
|
+
f" {total_errors} error(s), {total_warnings} warning(s).",
|
|
204
|
+
bold=True,
|
|
205
|
+
)
|
|
206
|
+
)
|
|
207
|
+
click.echo()
|
|
208
|
+
if total_errors:
|
|
209
|
+
raise SystemExit(1)
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
cli_command = check_contracts
|
|
@@ -196,31 +196,36 @@ def check_deps():
|
|
|
196
196
|
product = context.require_app()
|
|
197
197
|
product_dir = os.path.join(workspace, product)
|
|
198
198
|
|
|
199
|
-
# Read UVL
|
|
199
|
+
# Read the UVL: the named SPL model, or the legacy in-product file
|
|
200
|
+
from splent_cli.services import spl_store
|
|
201
|
+
|
|
200
202
|
try:
|
|
201
203
|
reader = PyprojectReader.for_product(product_dir)
|
|
202
|
-
# 1. Catalog: [tool.splent].spl
|
|
203
204
|
spl_name = reader.splent_config.get("spl")
|
|
204
205
|
if spl_name:
|
|
205
|
-
uvl_path =
|
|
206
|
-
|
|
207
|
-
|
|
206
|
+
uvl_path = spl_store.product_uvl(workspace, product, allow_fetch=True)
|
|
207
|
+
if not uvl_path:
|
|
208
|
+
click.secho(
|
|
209
|
+
" [x] " + spl_store.missing_model_message(workspace, spl_name),
|
|
210
|
+
fg="red",
|
|
211
|
+
)
|
|
212
|
+
raise SystemExit(1)
|
|
208
213
|
else:
|
|
209
214
|
# 2. Legacy: [tool.splent.uvl].file
|
|
210
215
|
uvl_file = reader.uvl_config.get("file")
|
|
211
216
|
if not uvl_file:
|
|
212
217
|
click.secho(
|
|
213
|
-
" [
|
|
218
|
+
" [x] No UVL configured. Set [tool.splent].spl or [tool.splent.uvl].file.",
|
|
214
219
|
fg="red",
|
|
215
220
|
)
|
|
216
221
|
raise SystemExit(1)
|
|
217
222
|
uvl_path = os.path.join(product_dir, "uvl", uvl_file)
|
|
218
223
|
except (FileNotFoundError, RuntimeError) as e:
|
|
219
|
-
click.secho(f" [
|
|
224
|
+
click.secho(f" [x] Cannot read pyproject.toml: {e}", fg="red")
|
|
220
225
|
raise SystemExit(1)
|
|
221
226
|
|
|
222
227
|
if not os.path.isfile(uvl_path):
|
|
223
|
-
click.secho(f" [
|
|
228
|
+
click.secho(f" [x] UVL file not found: {uvl_path}", fg="red")
|
|
224
229
|
raise SystemExit(1)
|
|
225
230
|
|
|
226
231
|
package_map, allowed_deps = _parse_uvl_deps(uvl_path)
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import click
|
|
2
|
+
|
|
3
|
+
from splent_cli.services import registry, release_gate
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@click.command(
|
|
7
|
+
"check:pypi",
|
|
8
|
+
short_help="Verify PyPI credentials from .env (TWINE_USERNAME / TWINE_PASSWORD)",
|
|
9
|
+
)
|
|
10
|
+
@click.option(
|
|
11
|
+
"--test", is_flag=True, default=False, help="Check against TestPyPI instead of PyPI"
|
|
12
|
+
)
|
|
13
|
+
def check_pypi(test: bool):
|
|
14
|
+
click.echo(click.style("\nPyPI Credentials Check\n", fg="cyan", bold=True))
|
|
15
|
+
|
|
16
|
+
# Exactly the credentials the upload will use, resolved once, so this
|
|
17
|
+
# command and the release gate can never disagree about what is configured.
|
|
18
|
+
resolved_user, resolved_password = release_gate.pypi_credentials()
|
|
19
|
+
username = (resolved_user or "").strip()
|
|
20
|
+
password = (resolved_password or "").strip()
|
|
21
|
+
|
|
22
|
+
registry_name = "TestPyPI" if test else "PyPI"
|
|
23
|
+
|
|
24
|
+
# --- presence checks ---
|
|
25
|
+
if not username:
|
|
26
|
+
click.echo(click.style("[✖] ", fg="red") + "TWINE_USERNAME not set in .env")
|
|
27
|
+
click.secho(
|
|
28
|
+
" Run 'splent tokens:setup' for setup instructions.", fg="bright_black"
|
|
29
|
+
)
|
|
30
|
+
raise SystemExit(1)
|
|
31
|
+
click.echo(click.style("[✔] ", fg="green") + f"TWINE_USERNAME = {username}")
|
|
32
|
+
|
|
33
|
+
if not password:
|
|
34
|
+
click.echo(
|
|
35
|
+
click.style("[✖] ", fg="red")
|
|
36
|
+
+ "TWINE_PASSWORD (or PYPI_PASSWORD) not set in .env"
|
|
37
|
+
)
|
|
38
|
+
click.secho(
|
|
39
|
+
" Run 'splent tokens:setup' for setup instructions.", fg="bright_black"
|
|
40
|
+
)
|
|
41
|
+
raise SystemExit(1)
|
|
42
|
+
|
|
43
|
+
masked = (
|
|
44
|
+
password[:4] + "*" * (len(password) - 8) + password[-4:]
|
|
45
|
+
if len(password) > 8
|
|
46
|
+
else "****"
|
|
47
|
+
)
|
|
48
|
+
click.echo(click.style("[✔] ", fg="green") + f"TWINE_PASSWORD = {masked}")
|
|
49
|
+
|
|
50
|
+
if username == "__token__" and not password.startswith("pypi-"):
|
|
51
|
+
click.echo(
|
|
52
|
+
click.style("[⚠] ", fg="yellow")
|
|
53
|
+
+ "TWINE_USERNAME is '__token__' but password doesn't start with 'pypi-', may be invalid"
|
|
54
|
+
)
|
|
55
|
+
elif username == "__token__":
|
|
56
|
+
click.echo(
|
|
57
|
+
click.style("[✔] ", fg="green") + "Token format looks correct (pypi-...)"
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
# --- verify via the upload endpoint (valid token -> 400, invalid -> 403/401) ---
|
|
61
|
+
# The probe itself lives in services/registry.py, the single PyPI boundary,
|
|
62
|
+
# so the release gate and this command read the same signal from the same
|
|
63
|
+
# request instead of two probes that can disagree.
|
|
64
|
+
click.echo(f"\nContacting {registry_name} API...")
|
|
65
|
+
try:
|
|
66
|
+
probe = registry.pypi_upload_probe(username, password, test=test)
|
|
67
|
+
except registry.RegistryError as e:
|
|
68
|
+
click.echo(click.style("[✖] ", fg="red") + f"{e}")
|
|
69
|
+
raise SystemExit(1)
|
|
70
|
+
|
|
71
|
+
if probe.rate_limited:
|
|
72
|
+
click.echo(
|
|
73
|
+
click.style("[✖] ", fg="red")
|
|
74
|
+
+ f"{registry_name} is RATE LIMITING this account (HTTP 429)"
|
|
75
|
+
)
|
|
76
|
+
click.secho(f" {release_gate.pypi_window(probe.retry_after)}", fg="yellow")
|
|
77
|
+
click.secho(
|
|
78
|
+
" The credentials are not the problem. Uploads will be refused until "
|
|
79
|
+
"the limit clears.",
|
|
80
|
+
fg="bright_black",
|
|
81
|
+
)
|
|
82
|
+
raise SystemExit(1)
|
|
83
|
+
|
|
84
|
+
if probe.status in (401, 403):
|
|
85
|
+
click.echo(
|
|
86
|
+
click.style("[✖] ", fg="red")
|
|
87
|
+
+ f"Credentials rejected by {registry_name} (HTTP {probe.status}), "
|
|
88
|
+
"token invalid or expired"
|
|
89
|
+
)
|
|
90
|
+
click.secho(
|
|
91
|
+
" Run 'splent tokens:setup' for instructions on obtaining a valid token.",
|
|
92
|
+
fg="bright_black",
|
|
93
|
+
)
|
|
94
|
+
raise SystemExit(1)
|
|
95
|
+
|
|
96
|
+
if probe.status == 400:
|
|
97
|
+
click.echo(
|
|
98
|
+
click.style("[✔] ", fg="green")
|
|
99
|
+
+ f"Credentials valid ({registry_name} returned 400, expected for an empty upload)"
|
|
100
|
+
)
|
|
101
|
+
elif 200 <= probe.status < 300:
|
|
102
|
+
click.echo(
|
|
103
|
+
click.style("[✔] ", fg="green") + f"Credentials accepted by {registry_name}"
|
|
104
|
+
)
|
|
105
|
+
else:
|
|
106
|
+
# An answer that is not a verdict is not a pass. The release gate
|
|
107
|
+
# refuses on this exact input, and the command an operator runs to
|
|
108
|
+
# decide whether to release must not be the more permissive of the two.
|
|
109
|
+
click.echo(
|
|
110
|
+
click.style("[✖] ", fg="red")
|
|
111
|
+
+ f"{registry_name} returned HTTP {probe.status}, which is not a usable "
|
|
112
|
+
"answer, so the credentials could NOT be confirmed"
|
|
113
|
+
)
|
|
114
|
+
if probe.detail:
|
|
115
|
+
click.secho(f" {probe.detail}", fg="bright_black")
|
|
116
|
+
click.secho(
|
|
117
|
+
" Retry once it answers normally. A release would be refused in this "
|
|
118
|
+
"state.",
|
|
119
|
+
fg="yellow",
|
|
120
|
+
)
|
|
121
|
+
raise SystemExit(1)
|
|
122
|
+
|
|
123
|
+
click.echo()
|
|
124
|
+
click.secho(f"PyPI credentials OK ({registry_name}).", fg="green")
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
cli_command = check_pypi
|
|
@@ -128,14 +128,24 @@ def check_pyproject():
|
|
|
128
128
|
# SPL / UVL
|
|
129
129
|
spl_name = splent.get("spl")
|
|
130
130
|
if spl_name:
|
|
131
|
-
|
|
132
|
-
|
|
131
|
+
from splent_cli.services import spl_store
|
|
132
|
+
|
|
133
|
+
pin = spl_store.read_pin(workspace, spl_name, product=product)
|
|
134
|
+
uvl_path = spl_store.find_uvl(
|
|
135
|
+
workspace, spl_name, version=pin.version, doi=pin.doi
|
|
133
136
|
)
|
|
134
|
-
if
|
|
135
|
-
_ok(f"SPL
|
|
137
|
+
if uvl_path:
|
|
138
|
+
_ok(f"SPL model {spl_name} (UVL found at {uvl_path})")
|
|
139
|
+
elif pin.fetchable:
|
|
140
|
+
_warn(
|
|
141
|
+
f"SPL model {spl_name} not downloaded yet, run: "
|
|
142
|
+
f"splent spl:fetch {spl_name}"
|
|
143
|
+
)
|
|
136
144
|
else:
|
|
137
145
|
_fail(
|
|
138
|
-
f"SPL
|
|
146
|
+
f"SPL model {spl_name} has no UVL on disk and no DOI recorded. "
|
|
147
|
+
f"Add [tool.splent.spl_model] with the DOI, or run: "
|
|
148
|
+
f"splent spl:create {spl_name}"
|
|
139
149
|
)
|
|
140
150
|
else:
|
|
141
151
|
# Legacy fallback
|