splent-cli 1.4.5__tar.gz → 1.5.1__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.4.5/src/splent_cli.egg-info → splent_cli-1.5.1}/PKG-INFO +3 -2
- {splent_cli-1.4.5 → splent_cli-1.5.1}/pyproject.toml +4 -2
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/database/db_migrate.py +6 -33
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/database/db_rollback.py +22 -1
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/database/db_upgrade.py +3 -1
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/feature/feature_add.py +29 -29
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/feature/feature_attach.py +22 -15
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/feature/feature_contract.py +4 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/feature/feature_create.py +4 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/feature/feature_detach.py +19 -22
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/feature/feature_edit.py +59 -118
- splent_cli-1.5.1/src/splent_cli/commands/feature/feature_refinement.py +879 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/feature/feature_release.py +39 -18
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/feature/feature_remove.py +18 -32
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/feature/feature_xray.py +206 -181
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/feature_compile.py +1 -1
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/product/product_build.py +25 -9
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/product/product_configure.py +6 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/product/product_create.py +64 -13
- splent_cli-1.5.1/src/splent_cli/commands/product/product_deploy.py +274 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/product/product_derive.py +7 -6
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/product/product_deselect.py +9 -4
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/product/product_env.py +32 -49
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/product/product_port.py +10 -8
- splent_cli-1.5.1/src/splent_cli/commands/product/product_restart.py +114 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/product/product_run.py +2 -3
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/product/product_up.py +22 -12
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/product/product_validate.py +11 -5
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/spl/spl_configs.py +5 -2
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/tokens.py +4 -1
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/uvl/uvl_utils.py +17 -2
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/services/compose.py +5 -3
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/services/context.py +3 -3
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/utils/feature_utils.py +89 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1/src/splent_cli.egg-info}/PKG-INFO +3 -2
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli.egg-info/SOURCES.txt +1 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli.egg-info/requires.txt +3 -1
- splent_cli-1.4.5/src/splent_cli/commands/product/product_deploy.py +0 -173
- splent_cli-1.4.5/src/splent_cli/commands/product/product_restart.py +0 -64
- {splent_cli-1.4.5 → splent_cli-1.5.1}/LICENSE +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/README.md +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/setup.cfg +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/__init__.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/__main__.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/cli.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/__init__.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/cache/__init__.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/cache/cache_clear.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/cache/cache_orphans.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/cache/cache_outdated.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/cache/cache_prune.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/cache/cache_size.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/cache/cache_status.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/cache/cache_usage.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/cache/cache_versions.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/check/__init__.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/check/check_deps.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/check/check_docker.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/check/check_env.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/check/check_features.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/check/check_github.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/check/check_infra.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/check/check_product.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/check/check_pypi.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/check/check_pyproject.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/clear_cache.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/clear_log.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/clear_uploads.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/command_create.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/coverage.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/database/db_console.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/database/db_dump.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/database/db_reset.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/database/db_restore.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/database/db_seed.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/database/db_status.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/doctor.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/env/env_list.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/env/env_set.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/env/env_show.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/export_puml.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/feature/feature_clone.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/feature/feature_delete.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/feature/feature_diff.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/feature/feature_discard.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/feature/feature_drift.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/feature/feature_env.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/feature/feature_fork.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/feature/feature_git.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/feature/feature_hook_add.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/feature/feature_hook_remove.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/feature/feature_hooks.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/feature/feature_inject_config.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/feature/feature_list.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/feature/feature_order.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/feature/feature_outdated.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/feature/feature_pin.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/feature/feature_pip_install.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/feature/feature_pull.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/feature/feature_rename.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/feature/feature_search.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/feature/feature_status.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/feature/feature_sync_template.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/feature/feature_test.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/feature/feature_translate.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/feature/feature_upgrade.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/feature/feature_versions.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/linter.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/locust.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/product/__init__.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/product/product_clean.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/product/product_commands.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/product/product_complete.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/product/product_config.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/product/product_console.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/product/product_down.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/product/product_drift.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/product/product_list.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/product/product_logs.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/product/product_missing.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/product/product_release.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/product/product_routes.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/product/product_select.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/product/product_shell.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/product/product_signals.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/product/product_status.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/product/product_sync.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/product/product_sync_template.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/product/product_test.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/release/__init__.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/release/release_core.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/selenium.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/spl/__init__.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/spl/spl_add_feature.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/spl/spl_create.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/spl/spl_deps.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/spl/spl_features.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/spl/spl_fetch.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/spl/spl_fix.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/spl/spl_info.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/spl/spl_list.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/spl/spl_utils.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/commands/version.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/services/__init__.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/services/preflight.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/services/release.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/utils/__init__.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/utils/cache_utils.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/utils/command_loader.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/utils/contract_freshness.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/utils/db_utils.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/utils/decorators.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/utils/dynamic_imports.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/utils/feature_installer.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/utils/git_url.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/utils/integrity.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/utils/lifecycle.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/utils/manifest.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/utils/path_utils.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli/utils/template_drift.py +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli.egg-info/dependency_links.txt +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/src/splent_cli.egg-info/entry_points.txt +0 -0
- {splent_cli-1.4.5 → splent_cli-1.5.1}/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.5.1
|
|
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
|
|
@@ -21,7 +21,6 @@ Requires-Dist: black==24.10.0; extra == "dev"
|
|
|
21
21
|
Requires-Dist: coverage==7.6.10; extra == "dev"
|
|
22
22
|
Requires-Dist: docker==7.1.0; extra == "dev"
|
|
23
23
|
Requires-Dist: Faker==33.3.1; extra == "dev"
|
|
24
|
-
Requires-Dist: flamapy==2.5.0; extra == "dev"
|
|
25
24
|
Requires-Dist: flake8==7.1.1; extra == "dev"
|
|
26
25
|
Requires-Dist: graphviz==0.20.3; extra == "dev"
|
|
27
26
|
Requires-Dist: iniconfig==2.0.0; extra == "dev"
|
|
@@ -37,6 +36,8 @@ Requires-Dist: selenium-wire==5.1.0; extra == "dev"
|
|
|
37
36
|
Requires-Dist: pip-tools==7.4.1; extra == "dev"
|
|
38
37
|
Requires-Dist: tomli_w==1.2.0; extra == "dev"
|
|
39
38
|
Requires-Dist: PyYAML==6.0.3; extra == "dev"
|
|
39
|
+
Provides-Extra: uvl
|
|
40
|
+
Requires-Dist: flamapy==2.5.0; extra == "uvl"
|
|
40
41
|
Dynamic: license-file
|
|
41
42
|
|
|
42
43
|
# SPLENT CLI
|
|
@@ -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.5.1"
|
|
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"
|
|
@@ -28,7 +28,6 @@ dev = [
|
|
|
28
28
|
"coverage==7.6.10",
|
|
29
29
|
"docker==7.1.0",
|
|
30
30
|
"Faker==33.3.1",
|
|
31
|
-
"flamapy==2.5.0",
|
|
32
31
|
"flake8==7.1.1",
|
|
33
32
|
"graphviz==0.20.3",
|
|
34
33
|
"iniconfig==2.0.0",
|
|
@@ -45,6 +44,9 @@ dev = [
|
|
|
45
44
|
"tomli_w==1.2.0",
|
|
46
45
|
"PyYAML==6.0.3"
|
|
47
46
|
]
|
|
47
|
+
uvl = [
|
|
48
|
+
"flamapy==2.5.0",
|
|
49
|
+
]
|
|
48
50
|
|
|
49
51
|
[project.scripts]
|
|
50
52
|
splent = "splent_cli.__main__:main"
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import os
|
|
2
2
|
|
|
3
3
|
import click
|
|
4
|
-
from
|
|
5
|
-
from flask_migrate import migrate as alembic_migrate, upgrade as alembic_upgrade
|
|
4
|
+
from flask_migrate import migrate as alembic_migrate
|
|
6
5
|
|
|
7
6
|
from splent_cli.utils.decorators import requires_db
|
|
8
7
|
from splent_cli.services import context
|
|
9
8
|
from splent_cli.utils.lifecycle import (
|
|
10
|
-
advance_state,
|
|
11
9
|
resolve_feature_key_from_entry,
|
|
12
10
|
require_editable,
|
|
13
11
|
)
|
|
@@ -53,16 +51,17 @@ def _is_empty_migration(path: str) -> bool:
|
|
|
53
51
|
short_help="Generate and apply migrations (all features or a single one).",
|
|
54
52
|
)
|
|
55
53
|
@click.argument("feature", required=False, default=None)
|
|
54
|
+
@click.option(
|
|
55
|
+
"-m", "message", default=None, help="Migration message (defaults to feature name)."
|
|
56
|
+
)
|
|
56
57
|
@context.requires_product
|
|
57
|
-
def db_migrate(feature):
|
|
58
|
+
def db_migrate(feature, message):
|
|
58
59
|
"""
|
|
59
60
|
Generate new migration files for features that have schema changes,
|
|
60
61
|
then apply all pending migrations.
|
|
61
62
|
|
|
62
63
|
Empty migrations (no schema changes detected) are automatically removed.
|
|
63
64
|
"""
|
|
64
|
-
app = current_app
|
|
65
|
-
|
|
66
65
|
if feature:
|
|
67
66
|
dirs = {}
|
|
68
67
|
mdir = MigrationManager.get_feature_migration_dir(feature)
|
|
@@ -84,7 +83,6 @@ def db_migrate(feature):
|
|
|
84
83
|
|
|
85
84
|
# Build entry→key lookup for manifest updates
|
|
86
85
|
product_path = PathUtils.get_app_base_dir()
|
|
87
|
-
product_name = os.getenv("SPLENT_APP", "")
|
|
88
86
|
entry_lookup = {}
|
|
89
87
|
for entry in get_features_from_pyproject() or []:
|
|
90
88
|
key, ns, name, version = resolve_feature_key_from_entry(entry)
|
|
@@ -110,7 +108,7 @@ def db_migrate(feature):
|
|
|
110
108
|
alembic_logger.setLevel(logging.WARNING)
|
|
111
109
|
|
|
112
110
|
try:
|
|
113
|
-
alembic_migrate(directory=mdir, message=feat)
|
|
111
|
+
alembic_migrate(directory=mdir, message=message or feat)
|
|
114
112
|
except Exception as e:
|
|
115
113
|
if os.getenv("SPLENT_DEBUG"):
|
|
116
114
|
click.secho(
|
|
@@ -142,30 +140,5 @@ def db_migrate(feature):
|
|
|
142
140
|
else:
|
|
143
141
|
click.echo(click.style(f" ✔ {feat}: up to date", fg="green"))
|
|
144
142
|
|
|
145
|
-
# Apply pending migrations
|
|
146
|
-
try:
|
|
147
|
-
alembic_upgrade(directory=mdir)
|
|
148
|
-
revision = MigrationManager.get_current_feature_revision(
|
|
149
|
-
feat, app.extensions["migrate"].db.engine
|
|
150
|
-
)
|
|
151
|
-
MigrationManager.update_feature_status(app, feat, revision)
|
|
152
|
-
click.echo(click.style(f" ✅ {feat} → {revision or 'head'}", fg="green"))
|
|
153
|
-
|
|
154
|
-
# Advance lifecycle state to "migrated"
|
|
155
|
-
info = entry_lookup.get(feat)
|
|
156
|
-
if info:
|
|
157
|
-
key, ns, name, version = info
|
|
158
|
-
advance_state(
|
|
159
|
-
product_path,
|
|
160
|
-
product_name,
|
|
161
|
-
key,
|
|
162
|
-
to="migrated",
|
|
163
|
-
namespace=ns,
|
|
164
|
-
name=name,
|
|
165
|
-
version=version,
|
|
166
|
-
)
|
|
167
|
-
except Exception as e:
|
|
168
|
-
click.echo(click.style(f" ❌ {feat}: {e}", fg="red"))
|
|
169
|
-
|
|
170
143
|
|
|
171
144
|
cli_command = db_migrate
|
|
@@ -206,7 +206,28 @@ def db_rollback(feature, steps, cascade):
|
|
|
206
206
|
)
|
|
207
207
|
break
|
|
208
208
|
except Exception as e:
|
|
209
|
-
click.secho(f"
|
|
209
|
+
click.secho(f" {feature}: {e}", fg="red")
|
|
210
|
+
raise SystemExit(1)
|
|
211
|
+
|
|
212
|
+
# Offer to delete migration files if fully rolled back to base
|
|
213
|
+
if revision is None:
|
|
214
|
+
versions_dir = os.path.join(mdir, "versions")
|
|
215
|
+
if os.path.isdir(versions_dir):
|
|
216
|
+
migration_files = [
|
|
217
|
+
f
|
|
218
|
+
for f in os.listdir(versions_dir)
|
|
219
|
+
if f.endswith(".py") and not f.startswith("__")
|
|
220
|
+
]
|
|
221
|
+
if migration_files and click.confirm(
|
|
222
|
+
f" Delete {len(migration_files)} migration file(s)?",
|
|
223
|
+
default=False,
|
|
224
|
+
):
|
|
225
|
+
for f in migration_files:
|
|
226
|
+
os.remove(os.path.join(versions_dir, f))
|
|
227
|
+
click.echo(
|
|
228
|
+
click.style(" deleted: ", dim=True)
|
|
229
|
+
+ f"{len(migration_files)} file(s)"
|
|
230
|
+
)
|
|
210
231
|
|
|
211
232
|
|
|
212
233
|
cli_command = db_rollback
|
|
@@ -59,15 +59,17 @@ def db_upgrade(feature):
|
|
|
59
59
|
import logging
|
|
60
60
|
|
|
61
61
|
logging.getLogger("alembic").setLevel(logging.WARNING)
|
|
62
|
+
logging.getLogger("alembic.runtime.migration").setLevel(logging.WARNING)
|
|
62
63
|
|
|
63
64
|
for feat, mdir in dirs.items():
|
|
64
65
|
try:
|
|
66
|
+
logging.getLogger("alembic.runtime.migration").setLevel(logging.WARNING)
|
|
65
67
|
alembic_upgrade(directory=mdir)
|
|
66
68
|
revision = MigrationManager.get_current_feature_revision(
|
|
67
69
|
feat, app.extensions["migrate"].db.engine
|
|
68
70
|
)
|
|
69
71
|
MigrationManager.update_feature_status(app, feat, revision)
|
|
70
|
-
click.echo(click.style(f"
|
|
72
|
+
click.echo(click.style(f" {feat} -> {revision or 'head'}", fg="green"))
|
|
71
73
|
|
|
72
74
|
# Advance lifecycle state to "migrated"
|
|
73
75
|
info = entry_lookup.get(feat)
|
|
@@ -3,7 +3,7 @@ import tomllib
|
|
|
3
3
|
import tomli_w
|
|
4
4
|
import click
|
|
5
5
|
from splent_cli.services import context
|
|
6
|
-
from splent_cli.utils.feature_utils import normalize_namespace
|
|
6
|
+
from splent_cli.utils.feature_utils import normalize_namespace, hot_reinstall
|
|
7
7
|
from splent_cli.utils.manifest import feature_key, set_feature_state
|
|
8
8
|
|
|
9
9
|
|
|
@@ -39,11 +39,8 @@ def feature_add(full_name, env_scope):
|
|
|
39
39
|
splent feature:add splent-io/splent_feature_admin --dev
|
|
40
40
|
"""
|
|
41
41
|
|
|
42
|
-
# --------------------------
|
|
43
|
-
# 0️⃣ Validate format
|
|
44
|
-
# --------------------------
|
|
45
42
|
if "/" not in full_name:
|
|
46
|
-
click.
|
|
43
|
+
click.secho(" Invalid format. Use: <namespace>/<feature_name>", fg="red")
|
|
47
44
|
raise SystemExit(1)
|
|
48
45
|
|
|
49
46
|
namespace, feature_name = full_name.split("/", 1)
|
|
@@ -55,16 +52,17 @@ def feature_add(full_name, env_scope):
|
|
|
55
52
|
# Editable features live at workspace root
|
|
56
53
|
feature_dir = os.path.join(workspace, feature_name)
|
|
57
54
|
if not os.path.exists(feature_dir):
|
|
58
|
-
click.
|
|
59
|
-
click.echo(
|
|
55
|
+
click.secho(f" {feature_name} not found at workspace root.", fg="red")
|
|
56
|
+
click.echo(
|
|
57
|
+
click.style(" create it first: ", dim=True)
|
|
58
|
+
+ f"splent feature:create {full_name}"
|
|
59
|
+
)
|
|
60
60
|
raise SystemExit(1)
|
|
61
61
|
|
|
62
|
-
#
|
|
63
|
-
# 1️⃣ Update pyproject.toml
|
|
64
|
-
# --------------------------
|
|
62
|
+
# ── Update pyproject.toml ─────────────────────────────────────────
|
|
65
63
|
pyproject_path = os.path.join(workspace, product, "pyproject.toml")
|
|
66
64
|
if not os.path.exists(pyproject_path):
|
|
67
|
-
click.
|
|
65
|
+
click.secho(" pyproject.toml not found.", fg="red")
|
|
68
66
|
raise SystemExit(1)
|
|
69
67
|
|
|
70
68
|
with open(pyproject_path, "rb") as f:
|
|
@@ -82,19 +80,21 @@ def feature_add(full_name, env_scope):
|
|
|
82
80
|
else (data.get("tool", {}).get("splent", {}).get(features_key, []))
|
|
83
81
|
)
|
|
84
82
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
83
|
+
short = feature_name.replace("splent_feature_", "")
|
|
84
|
+
|
|
85
|
+
if full_name in features:
|
|
86
|
+
click.echo(f" {short} already in {features_key}.")
|
|
87
|
+
return
|
|
88
|
+
|
|
89
|
+
features.append(full_name)
|
|
90
|
+
write_features_to_data(data, features, key=features_key)
|
|
91
|
+
with open(pyproject_path, "wb") as f:
|
|
92
|
+
tomli_w.dump(data, f)
|
|
93
|
+
|
|
94
|
+
scope_label = f" ({env_scope} only)" if env_scope else ""
|
|
95
|
+
click.echo(f" {short} added to {features_key}{scope_label}")
|
|
96
|
+
|
|
97
|
+
# ── Create symlink ────────────────────────────────────────────────
|
|
98
98
|
product_features_dir = os.path.join(workspace, product, "features", org_safe)
|
|
99
99
|
os.makedirs(product_features_dir, exist_ok=True)
|
|
100
100
|
|
|
@@ -105,11 +105,8 @@ def feature_add(full_name, env_scope):
|
|
|
105
105
|
except FileExistsError:
|
|
106
106
|
os.unlink(link_path)
|
|
107
107
|
os.symlink(rel_target, link_path)
|
|
108
|
-
click.echo(f"🔗 Linked {link_path} → {rel_target}")
|
|
109
108
|
|
|
110
|
-
#
|
|
111
|
-
# 3️⃣ Update manifest
|
|
112
|
-
# --------------------------
|
|
109
|
+
# ── Update manifest ───────────────────────────────────────────────
|
|
113
110
|
product_path = os.path.join(workspace, product)
|
|
114
111
|
key = feature_key(namespace, feature_name)
|
|
115
112
|
set_feature_state(
|
|
@@ -123,4 +120,7 @@ def feature_add(full_name, env_scope):
|
|
|
123
120
|
mode="editable",
|
|
124
121
|
)
|
|
125
122
|
|
|
126
|
-
|
|
123
|
+
# ── Hot reinstall in web container ────────────────────────────────
|
|
124
|
+
hot_reinstall(product_path, f"/workspace/{feature_name}", feature_name)
|
|
125
|
+
|
|
126
|
+
click.secho(" done.", fg="green")
|
|
@@ -3,6 +3,7 @@ import tomllib
|
|
|
3
3
|
import tomli_w
|
|
4
4
|
import click
|
|
5
5
|
from splent_cli.services import context, compose
|
|
6
|
+
from splent_cli.utils.feature_utils import hot_reinstall
|
|
6
7
|
from splent_cli.utils.manifest import feature_key, set_feature_state
|
|
7
8
|
|
|
8
9
|
|
|
@@ -32,7 +33,7 @@ def feature_attach(feature_identifier, version, env_scope):
|
|
|
32
33
|
If not, run: splent feature:clone <namespace>/<feature>@<version>
|
|
33
34
|
- Updates pyproject.toml referencing feature@version.
|
|
34
35
|
- Creates/updates the versioned symlink in features/<namespace>/.
|
|
35
|
-
-
|
|
36
|
+
- Reinstalls the feature in the web container for hot reload.
|
|
36
37
|
"""
|
|
37
38
|
product = context.require_app()
|
|
38
39
|
ws = context.workspace()
|
|
@@ -47,22 +48,23 @@ def feature_attach(feature_identifier, version, env_scope):
|
|
|
47
48
|
pyproject_path = os.path.join(product_path, "pyproject.toml")
|
|
48
49
|
|
|
49
50
|
if not os.path.exists(pyproject_path):
|
|
50
|
-
click.
|
|
51
|
+
click.secho(" pyproject.toml not found.", fg="red")
|
|
51
52
|
raise SystemExit(1)
|
|
52
53
|
|
|
53
|
-
#
|
|
54
|
+
# ── Verify feature exists in cache ────────────────────────────────
|
|
54
55
|
versioned_dir = os.path.join(cache_base, f"{feature_name}@{version}")
|
|
55
56
|
|
|
56
57
|
if not os.path.exists(versioned_dir):
|
|
58
|
+
click.secho(f" {feature_name}@{version} not found in cache.", fg="red")
|
|
57
59
|
click.echo(
|
|
58
|
-
|
|
59
|
-
f"
|
|
60
|
+
click.style(" clone it first: ", dim=True)
|
|
61
|
+
+ f"splent feature:clone {namespace}/{feature_name}@{version}"
|
|
60
62
|
)
|
|
61
63
|
raise SystemExit(1)
|
|
62
64
|
|
|
63
|
-
|
|
65
|
+
short = feature_name.replace("splent_feature_", "")
|
|
64
66
|
|
|
65
|
-
#
|
|
67
|
+
# ── Update pyproject.toml ─────────────────────────────────────────
|
|
66
68
|
full_name = f"{namespace}/{feature_name}@{version}"
|
|
67
69
|
bare_name = f"{namespace}/{feature_name}"
|
|
68
70
|
|
|
@@ -82,9 +84,9 @@ def feature_attach(feature_identifier, version, env_scope):
|
|
|
82
84
|
)
|
|
83
85
|
|
|
84
86
|
if full_name in features:
|
|
85
|
-
click.echo(f"
|
|
87
|
+
click.echo(f" {short}@{version} already in {features_key}.")
|
|
86
88
|
else:
|
|
87
|
-
# Replace bare entry
|
|
89
|
+
# Replace bare entry or old versioned entry if present
|
|
88
90
|
features = [
|
|
89
91
|
f for f in features if f != bare_name and not f.startswith(f"{bare_name}@")
|
|
90
92
|
]
|
|
@@ -93,9 +95,9 @@ def feature_attach(feature_identifier, version, env_scope):
|
|
|
93
95
|
with open(pyproject_path, "wb") as f:
|
|
94
96
|
tomli_w.dump(data, f)
|
|
95
97
|
scope_label = f" ({env_scope} only)" if env_scope else ""
|
|
96
|
-
click.echo(f"
|
|
98
|
+
click.echo(f" {short}@{version} attached{scope_label}")
|
|
97
99
|
|
|
98
|
-
#
|
|
100
|
+
# ── Create/update symlink ─────────────────────────────────────────
|
|
99
101
|
product_features_dir = os.path.join(product_path, "features", namespace_fs)
|
|
100
102
|
os.makedirs(product_features_dir, exist_ok=True)
|
|
101
103
|
|
|
@@ -105,9 +107,7 @@ def feature_attach(feature_identifier, version, env_scope):
|
|
|
105
107
|
rel_target = os.path.relpath(versioned_dir, product_features_dir)
|
|
106
108
|
os.symlink(rel_target, new_link)
|
|
107
109
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
# --- 4️⃣ Update manifest ------------------------------------------------
|
|
110
|
+
# ── Update manifest ───────────────────────────────────────────────
|
|
111
111
|
key = feature_key(namespace_fs, feature_name, version)
|
|
112
112
|
set_feature_state(
|
|
113
113
|
product_path,
|
|
@@ -120,4 +120,11 @@ def feature_attach(feature_identifier, version, env_scope):
|
|
|
120
120
|
mode="pinned",
|
|
121
121
|
)
|
|
122
122
|
|
|
123
|
-
|
|
123
|
+
# ── Hot reinstall in web container ────────────────────────────────
|
|
124
|
+
# Symlink resolves to cache path — install from there
|
|
125
|
+
install_path = (
|
|
126
|
+
f"/workspace/{product}/features/{namespace_fs}/{feature_name}@{version}"
|
|
127
|
+
)
|
|
128
|
+
hot_reinstall(product_path, install_path, feature_name)
|
|
129
|
+
|
|
130
|
+
click.secho(" done.", fg="green")
|
|
@@ -175,6 +175,10 @@ def _print_diff(current: dict, inferred: dict) -> bool:
|
|
|
175
175
|
("signals", "provides.signals"),
|
|
176
176
|
("translations", "provides.translations"),
|
|
177
177
|
("requires_signals", "requires.signals"),
|
|
178
|
+
("extensible_services", "extensible.services"),
|
|
179
|
+
("extensible_templates", "extensible.templates"),
|
|
180
|
+
("extensible_models", "extensible.models"),
|
|
181
|
+
("extensible_hooks", "extensible.hooks"),
|
|
178
182
|
]
|
|
179
183
|
|
|
180
184
|
diff_lines = []
|
|
@@ -88,9 +88,13 @@ def make_feature(full_name):
|
|
|
88
88
|
if short_name.startswith("splent_feature_"):
|
|
89
89
|
short_name = short_name[len("splent_feature_") :]
|
|
90
90
|
|
|
91
|
+
# PascalCase for class names: notes_tags → NotesTags
|
|
92
|
+
pascal_name = "".join(w.capitalize() for w in short_name.split("_"))
|
|
93
|
+
|
|
91
94
|
template_ctx = {
|
|
92
95
|
"feature_name": feature_name,
|
|
93
96
|
"short_name": short_name,
|
|
97
|
+
"pascal_name": pascal_name,
|
|
94
98
|
"org_safe": org_safe,
|
|
95
99
|
"feature_import": f"{org_safe}.{feature_name}",
|
|
96
100
|
"cli_version": _CLI_VERSION,
|
|
@@ -2,6 +2,7 @@ import os
|
|
|
2
2
|
import re
|
|
3
3
|
import click
|
|
4
4
|
from splent_cli.services import context, compose
|
|
5
|
+
from splent_cli.utils.feature_utils import hot_uninstall
|
|
5
6
|
from splent_cli.utils.manifest import (
|
|
6
7
|
feature_key,
|
|
7
8
|
remove_feature,
|
|
@@ -39,39 +40,37 @@ def feature_detach(feature_identifier, version, force):
|
|
|
39
40
|
|
|
40
41
|
product_path = str(ws / product)
|
|
41
42
|
pyproject_path = os.path.join(product_path, "pyproject.toml")
|
|
43
|
+
short = feature_name.replace("splent_feature_", "")
|
|
42
44
|
|
|
43
45
|
if not os.path.exists(pyproject_path):
|
|
44
|
-
click.
|
|
46
|
+
click.secho(" pyproject.toml not found.", fg="red")
|
|
45
47
|
raise SystemExit(1)
|
|
46
48
|
|
|
47
49
|
if not force:
|
|
48
|
-
#
|
|
50
|
+
# Guard: dependency check
|
|
49
51
|
dependents = get_dependents(product_path, feature_name)
|
|
50
52
|
if dependents:
|
|
51
53
|
click.secho(
|
|
52
|
-
f"
|
|
53
|
-
+ "".join(f"
|
|
54
|
-
+ "
|
|
54
|
+
f" Cannot detach '{short}': the following features depend on it:\n"
|
|
55
|
+
+ "".join(f" - {d}\n" for d in dependents)
|
|
56
|
+
+ " Remove those first, or use --force.",
|
|
55
57
|
fg="red",
|
|
56
58
|
)
|
|
57
59
|
raise SystemExit(1)
|
|
58
60
|
|
|
59
|
-
#
|
|
61
|
+
# Guard: migration state
|
|
60
62
|
key = feature_key(namespace_fs, feature_name, version)
|
|
61
63
|
state = get_feature_state(product_path, key)
|
|
62
64
|
if state in ("migrated", "active"):
|
|
63
65
|
click.secho(
|
|
64
|
-
f"
|
|
65
|
-
f"
|
|
66
|
-
f"
|
|
67
|
-
f" Or use --force to skip this check.",
|
|
66
|
+
f" {short} has migrations applied (state: {state}).\n"
|
|
67
|
+
f" Roll them back first: splent db:rollback {feature_name} --steps 999\n"
|
|
68
|
+
f" Or use --force.",
|
|
68
69
|
fg="red",
|
|
69
70
|
)
|
|
70
71
|
raise SystemExit(1)
|
|
71
72
|
|
|
72
|
-
#
|
|
73
|
-
click.echo(f"🧹 Removing {feature_name}@{version} from pyproject.toml...")
|
|
74
|
-
|
|
73
|
+
# ── Remove versioned reference from pyproject ─────────────────────
|
|
75
74
|
with open(pyproject_path, "r", encoding="utf-8") as f:
|
|
76
75
|
content = f.read()
|
|
77
76
|
|
|
@@ -81,22 +80,20 @@ def feature_detach(feature_identifier, version, force):
|
|
|
81
80
|
with open(pyproject_path, "w", encoding="utf-8") as f:
|
|
82
81
|
f.write(new_content)
|
|
83
82
|
|
|
84
|
-
click.echo("
|
|
83
|
+
click.echo(f" {short}@{version} removed from pyproject.toml")
|
|
85
84
|
|
|
86
|
-
#
|
|
85
|
+
# ── Remove symlink ────────────────────────────────────────────────
|
|
87
86
|
product_features_dir = os.path.join(product_path, "features", namespace_fs)
|
|
88
87
|
link_path = os.path.join(product_features_dir, f"{feature_name}@{version}")
|
|
89
88
|
|
|
90
89
|
if os.path.islink(link_path):
|
|
91
90
|
os.unlink(link_path)
|
|
92
|
-
click.echo(f"🔗 Removed symlink: {link_path}")
|
|
93
|
-
else:
|
|
94
|
-
click.echo(
|
|
95
|
-
f"⚠️ No symlink found for {feature_name}@{version} in {namespace_fs}/"
|
|
96
|
-
)
|
|
97
91
|
|
|
98
|
-
#
|
|
92
|
+
# ── Update manifest ───────────────────────────────────────────────
|
|
99
93
|
key = feature_key(namespace_fs, feature_name, version)
|
|
100
94
|
remove_feature(str(ws / product), product, key)
|
|
101
95
|
|
|
102
|
-
|
|
96
|
+
# ── Hot uninstall from web container ──────────────────────────────
|
|
97
|
+
hot_uninstall(product_path, feature_name)
|
|
98
|
+
|
|
99
|
+
click.secho(" done.", fg="green")
|