splent-cli 1.4.3__tar.gz → 1.4.4__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.
Files changed (160) hide show
  1. {splent_cli-1.4.3/src/splent_cli.egg-info → splent_cli-1.4.4}/PKG-INFO +1 -1
  2. {splent_cli-1.4.3 → splent_cli-1.4.4}/pyproject.toml +1 -1
  3. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/cli.py +8 -5
  4. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/check/check_deps.py +7 -5
  5. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/check/check_infra.py +29 -12
  6. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/check/check_product.py +23 -8
  7. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/clear_cache.py +5 -6
  8. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/database/db_dump.py +1 -3
  9. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/database/db_rollback.py +28 -11
  10. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/database/db_seed.py +7 -2
  11. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/database/db_status.py +1 -0
  12. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/export_puml.py +2 -3
  13. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/feature/feature_add.py +16 -4
  14. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/feature/feature_attach.py +16 -4
  15. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/feature/feature_clone.py +9 -3
  16. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/feature/feature_contract.py +11 -3
  17. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/feature/feature_create.py +1 -1
  18. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/feature/feature_diff.py +1 -0
  19. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/feature/feature_edit.py +5 -4
  20. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/feature/feature_inject_config.py +3 -2
  21. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/feature/feature_order.py +11 -5
  22. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/feature/feature_outdated.py +21 -6
  23. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/feature/feature_pin.py +10 -8
  24. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/feature/feature_pip_install.py +6 -2
  25. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/feature/feature_release.py +39 -11
  26. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/feature/feature_status.py +21 -10
  27. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/feature/feature_translate.py +16 -6
  28. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/feature/feature_upgrade.py +1 -0
  29. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/feature/feature_xray.py +127 -49
  30. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/locust.py +2 -6
  31. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/product/product_build.py +6 -2
  32. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/product/product_clean.py +7 -2
  33. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/product/product_commands.py +1 -3
  34. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/product/product_complete.py +3 -1
  35. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/product/product_config.py +41 -37
  36. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/product/product_configure.py +45 -53
  37. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/product/product_console.py +1 -6
  38. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/product/product_create.py +11 -4
  39. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/product/product_deploy.py +3 -1
  40. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/product/product_derive.py +37 -20
  41. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/product/product_deselect.py +1 -3
  42. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/product/product_down.py +1 -1
  43. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/product/product_release.py +10 -4
  44. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/product/product_restart.py +8 -2
  45. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/product/product_routes.py +7 -2
  46. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/product/product_select.py +1 -0
  47. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/product/product_signals.py +4 -4
  48. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/product/product_sync.py +5 -5
  49. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/product/product_test.py +12 -3
  50. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/product/product_validate.py +7 -3
  51. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/spl/spl_add_feature.py +34 -16
  52. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/spl/spl_configs.py +4 -5
  53. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/spl/spl_create.py +4 -10
  54. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/spl/spl_deps.py +1 -1
  55. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/spl/spl_features.py +1 -1
  56. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/spl/spl_fix.py +1 -3
  57. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/spl/spl_list.py +6 -2
  58. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/spl/spl_utils.py +2 -6
  59. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/uvl/uvl_utils.py +8 -3
  60. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/services/context.py +1 -2
  61. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/services/preflight.py +0 -2
  62. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/services/release.py +68 -21
  63. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/utils/contract_freshness.py +3 -6
  64. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/utils/git_url.py +9 -2
  65. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/utils/integrity.py +60 -37
  66. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/utils/template_drift.py +1 -1
  67. {splent_cli-1.4.3 → splent_cli-1.4.4/src/splent_cli.egg-info}/PKG-INFO +1 -1
  68. {splent_cli-1.4.3 → splent_cli-1.4.4}/LICENSE +0 -0
  69. {splent_cli-1.4.3 → splent_cli-1.4.4}/README.md +0 -0
  70. {splent_cli-1.4.3 → splent_cli-1.4.4}/setup.cfg +0 -0
  71. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/__init__.py +0 -0
  72. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/__main__.py +0 -0
  73. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/__init__.py +0 -0
  74. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/cache/__init__.py +0 -0
  75. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/cache/cache_clear.py +0 -0
  76. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/cache/cache_orphans.py +0 -0
  77. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/cache/cache_outdated.py +0 -0
  78. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/cache/cache_prune.py +0 -0
  79. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/cache/cache_size.py +0 -0
  80. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/cache/cache_status.py +0 -0
  81. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/cache/cache_usage.py +0 -0
  82. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/cache/cache_versions.py +0 -0
  83. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/check/__init__.py +0 -0
  84. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/check/check_docker.py +0 -0
  85. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/check/check_env.py +0 -0
  86. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/check/check_features.py +0 -0
  87. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/check/check_github.py +0 -0
  88. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/check/check_pypi.py +0 -0
  89. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/check/check_pyproject.py +0 -0
  90. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/clear_log.py +0 -0
  91. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/clear_uploads.py +0 -0
  92. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/command_create.py +0 -0
  93. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/coverage.py +0 -0
  94. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/database/db_console.py +0 -0
  95. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/database/db_migrate.py +0 -0
  96. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/database/db_reset.py +0 -0
  97. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/database/db_restore.py +0 -0
  98. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/database/db_upgrade.py +0 -0
  99. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/doctor.py +0 -0
  100. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/env/env_list.py +0 -0
  101. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/env/env_set.py +0 -0
  102. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/env/env_show.py +0 -0
  103. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/feature/feature_delete.py +0 -0
  104. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/feature/feature_detach.py +0 -0
  105. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/feature/feature_discard.py +0 -0
  106. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/feature/feature_drift.py +0 -0
  107. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/feature/feature_env.py +0 -0
  108. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/feature/feature_fork.py +0 -0
  109. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/feature/feature_git.py +0 -0
  110. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/feature/feature_hook_add.py +0 -0
  111. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/feature/feature_hook_remove.py +0 -0
  112. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/feature/feature_hooks.py +0 -0
  113. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/feature/feature_list.py +0 -0
  114. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/feature/feature_pull.py +0 -0
  115. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/feature/feature_remove.py +0 -0
  116. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/feature/feature_rename.py +0 -0
  117. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/feature/feature_search.py +0 -0
  118. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/feature/feature_sync_template.py +0 -0
  119. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/feature/feature_test.py +0 -0
  120. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/feature/feature_versions.py +0 -0
  121. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/feature_compile.py +0 -0
  122. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/linter.py +0 -0
  123. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/product/__init__.py +0 -0
  124. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/product/product_drift.py +0 -0
  125. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/product/product_env.py +0 -0
  126. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/product/product_list.py +0 -0
  127. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/product/product_logs.py +0 -0
  128. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/product/product_missing.py +0 -0
  129. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/product/product_port.py +0 -0
  130. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/product/product_run.py +0 -0
  131. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/product/product_shell.py +0 -0
  132. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/product/product_status.py +0 -0
  133. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/product/product_sync_template.py +0 -0
  134. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/product/product_up.py +0 -0
  135. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/release/__init__.py +0 -0
  136. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/release/release_core.py +0 -0
  137. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/selenium.py +0 -0
  138. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/spl/__init__.py +0 -0
  139. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/spl/spl_fetch.py +0 -0
  140. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/spl/spl_info.py +0 -0
  141. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/tokens.py +0 -0
  142. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/commands/version.py +0 -0
  143. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/services/__init__.py +0 -0
  144. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/services/compose.py +0 -0
  145. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/utils/__init__.py +0 -0
  146. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/utils/cache_utils.py +0 -0
  147. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/utils/command_loader.py +0 -0
  148. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/utils/db_utils.py +0 -0
  149. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/utils/decorators.py +0 -0
  150. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/utils/dynamic_imports.py +0 -0
  151. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/utils/feature_installer.py +0 -0
  152. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/utils/feature_utils.py +0 -0
  153. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/utils/lifecycle.py +0 -0
  154. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/utils/manifest.py +0 -0
  155. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli/utils/path_utils.py +0 -0
  156. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli.egg-info/SOURCES.txt +0 -0
  157. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli.egg-info/dependency_links.txt +0 -0
  158. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli.egg-info/entry_points.txt +0 -0
  159. {splent_cli-1.4.3 → splent_cli-1.4.4}/src/splent_cli.egg-info/requires.txt +0 -0
  160. {splent_cli-1.4.3 → splent_cli-1.4.4}/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.4.3
3
+ Version: 1.4.4
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
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "splent_cli"
7
- version = "1.4.3"
7
+ version = "1.4.4"
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"
@@ -54,7 +54,9 @@ class SPLENTCLI(click.Group):
54
54
  self._feature_cmds_cache[group.name] = group
55
55
  except Exception as e:
56
56
  if os.getenv("SPLENT_DEBUG"):
57
- click.secho(f" ⚠ Feature commands not loaded: {e}", fg="yellow", err=True)
57
+ click.secho(
58
+ f" ⚠ Feature commands not loaded: {e}", fg="yellow", err=True
59
+ )
58
60
  return self._feature_cmds_cache
59
61
 
60
62
  def get_command(self, ctx, cmd_name):
@@ -92,8 +94,10 @@ class SPLENTCLI(click.Group):
92
94
  all_cmds = self.list_commands(ctx)
93
95
  groups = {
94
96
  "🌿 Feature Management": [
95
- cmd for cmd in all_cmds
96
- if cmd.startswith("feature:") and cmd not in self._load_feature_commands()
97
+ cmd
98
+ for cmd in all_cmds
99
+ if cmd.startswith("feature:")
100
+ and cmd not in self._load_feature_commands()
97
101
  ],
98
102
  "🏗️ Product Management": [
99
103
  cmd for cmd in all_cmds if cmd.startswith("product:")
@@ -116,8 +120,7 @@ class SPLENTCLI(click.Group):
116
120
  if cmd.startswith(("linter", "test", "coverage", "locust"))
117
121
  ],
118
122
  "🔌 Feature Commands": [
119
- cmd for cmd in all_cmds
120
- if cmd in self._load_feature_commands()
123
+ cmd for cmd in all_cmds if cmd in self._load_feature_commands()
121
124
  ],
122
125
  }
123
126
  for title, cmds in groups.items():
@@ -202,12 +202,17 @@ def check_deps():
202
202
  # 1. Catalog: [tool.splent].spl
203
203
  spl_name = reader.splent_config.get("spl")
204
204
  if spl_name:
205
- uvl_path = os.path.join(workspace, "splent_catalog", spl_name, f"{spl_name}.uvl")
205
+ uvl_path = os.path.join(
206
+ workspace, "splent_catalog", spl_name, f"{spl_name}.uvl"
207
+ )
206
208
  else:
207
209
  # 2. Legacy: [tool.splent.uvl].file
208
210
  uvl_file = reader.uvl_config.get("file")
209
211
  if not uvl_file:
210
- click.secho(" [✖] No UVL configured. Set [tool.splent].spl or [tool.splent.uvl].file.", fg="red")
212
+ click.secho(
213
+ " [✖] No UVL configured. Set [tool.splent].spl or [tool.splent.uvl].file.",
214
+ fg="red",
215
+ )
211
216
  raise SystemExit(1)
212
217
  uvl_path = os.path.join(product_dir, "uvl", uvl_file)
213
218
  except (FileNotFoundError, RuntimeError) as e:
@@ -256,8 +261,6 @@ def check_deps():
256
261
  ok += 1
257
262
  continue
258
263
 
259
- has_violation = False
260
-
261
264
  for imp in sorted(all_deps):
262
265
  imp_short = pkg_to_short.get(imp, imp)
263
266
  source = "imports" if imp in py_imports else "references (template)"
@@ -295,7 +298,6 @@ def check_deps():
295
298
  )
296
299
  )
297
300
  violations += 1
298
- has_violation = True
299
301
 
300
302
  click.echo()
301
303
  if violations:
@@ -17,7 +17,8 @@ def _parse_compose_ports(compose_file: str) -> list[tuple[int, str, str]]:
17
17
  """Return [(host_port, service_name, source_label)] from a compose file."""
18
18
  result = subprocess.run(
19
19
  ["docker", "compose", "-f", compose_file, "config", "--format", "json"],
20
- capture_output=True, text=True,
20
+ capture_output=True,
21
+ text=True,
21
22
  )
22
23
  if result.returncode != 0:
23
24
  return []
@@ -42,7 +43,8 @@ def _parse_compose_services(compose_file: str) -> list[tuple[str, str, str]]:
42
43
  """Return [(service_name, container_name_or_None, source_label)]."""
43
44
  result = subprocess.run(
44
45
  ["docker", "compose", "-f", compose_file, "config", "--format", "json"],
45
- capture_output=True, text=True,
46
+ capture_output=True,
47
+ text=True,
46
48
  )
47
49
  if result.returncode != 0:
48
50
  return []
@@ -58,7 +60,10 @@ def _parse_compose_services(compose_file: str) -> list[tuple[str, str, str]]:
58
60
  return services
59
61
 
60
62
 
61
- @click.command("check:infra", short_help="Validate Docker infrastructure (ports, services, networks).")
63
+ @click.command(
64
+ "check:infra",
65
+ short_help="Validate Docker infrastructure (ports, services, networks).",
66
+ )
62
67
  def check_infra():
63
68
  """Check for port conflicts, duplicate services, container name collisions,
64
69
  and network availability across all features and the product."""
@@ -132,7 +137,8 @@ def check_infra():
132
137
  for port in all_ports:
133
138
  result = subprocess.run(
134
139
  ["docker", "ps", "--format", "{{.ID}}\t{{.Names}}\t{{.Ports}}"],
135
- capture_output=True, text=True,
140
+ capture_output=True,
141
+ text=True,
136
142
  )
137
143
  for line in result.stdout.splitlines():
138
144
  parts = line.split("\t", 2)
@@ -170,9 +176,13 @@ def check_infra():
170
176
  cn_conflicts = {c: srcs for c, srcs in all_container_names.items() if len(srcs) > 1}
171
177
  if cn_conflicts:
172
178
  for cn, sources in sorted(cn_conflicts.items()):
173
- _fail(f"Container name '{cn}' used by multiple features: {', '.join(sources)}")
179
+ _fail(
180
+ f"Container name '{cn}' used by multiple features: {', '.join(sources)}"
181
+ )
174
182
  else:
175
- _ok(f"No container name collisions ({len(all_container_names)} named containers)")
183
+ _ok(
184
+ f"No container name collisions ({len(all_container_names)} named containers)"
185
+ )
176
186
 
177
187
  # --- Check 3: Network availability ---
178
188
  click.echo()
@@ -181,7 +191,8 @@ def check_infra():
181
191
  for label, cf in compose_files:
182
192
  result = subprocess.run(
183
193
  ["docker", "compose", "-f", cf, "config", "--format", "json"],
184
- capture_output=True, text=True,
194
+ capture_output=True,
195
+ text=True,
185
196
  )
186
197
  if result.returncode != 0:
187
198
  continue
@@ -196,24 +207,30 @@ def check_infra():
196
207
  if required_networks:
197
208
  existing_networks = subprocess.run(
198
209
  ["docker", "network", "ls", "--format", "{{.Name}}"],
199
- capture_output=True, text=True,
210
+ capture_output=True,
211
+ text=True,
200
212
  ).stdout.splitlines()
201
213
  for net in sorted(required_networks):
202
214
  if net in existing_networks:
203
215
  _ok(f"Network '{net}' exists")
204
216
  else:
205
- _fail(f"External network '{net}' does not exist (run: docker network create {net})")
217
+ _fail(
218
+ f"External network '{net}' does not exist (run: docker network create {net})"
219
+ )
206
220
  else:
207
221
  _ok("No external networks required")
208
222
 
209
223
  # --- Summary ---
210
224
  click.echo()
211
- total = ok + fail + warn
212
225
  if fail:
213
- click.secho(f" {fail} check(s) failed, {warn} warning(s), {ok} passed.", fg="red")
226
+ click.secho(
227
+ f" {fail} check(s) failed, {warn} warning(s), {ok} passed.", fg="red"
228
+ )
214
229
  raise SystemExit(1)
215
230
  elif warn:
216
- click.secho(f" All passed with {warn} warning(s) ({ok} checks OK).", fg="yellow")
231
+ click.secho(
232
+ f" All passed with {warn} warning(s) ({ok} checks OK).", fg="yellow"
233
+ )
217
234
  else:
218
235
  click.secho(f" All {ok} checks passed.", fg="green")
219
236
  click.echo()
@@ -16,7 +16,6 @@ import click
16
16
  from splent_cli.services import context
17
17
  from splent_cli.utils.feature_utils import (
18
18
  load_product_features,
19
- normalize_namespace,
20
19
  parse_feature_entry,
21
20
  )
22
21
 
@@ -31,7 +30,9 @@ def _resolve_feature_pyproject(workspace, product_path, ns_safe, name, version):
31
30
 
32
31
  # 2. Product symlink
33
32
  dir_name = f"{name}@{version}" if version else name
34
- candidate = os.path.join(product_path, "features", ns_safe, dir_name, "pyproject.toml")
33
+ candidate = os.path.join(
34
+ product_path, "features", ns_safe, dir_name, "pyproject.toml"
35
+ )
35
36
  if os.path.isfile(candidate):
36
37
  with open(candidate, "rb") as f:
37
38
  return tomllib.load(f)
@@ -85,7 +86,9 @@ def _check_env_vars(workspace, product_path, features, counters):
85
86
  per_feature: dict[str, list[str]] = {}
86
87
  for entry in features:
87
88
  ns_safe, name, version = parse_feature_entry(entry)
88
- data = _resolve_feature_pyproject(workspace, product_path, ns_safe, name, version)
89
+ data = _resolve_feature_pyproject(
90
+ workspace, product_path, ns_safe, name, version
91
+ )
89
92
  if not data:
90
93
  continue
91
94
  env_vars = (
@@ -106,6 +109,7 @@ def _check_env_vars(workspace, product_path, features, counters):
106
109
  injected_keys: set[str] = set()
107
110
  try:
108
111
  from splent_cli.utils.dynamic_imports import get_app
112
+
109
113
  app = get_app()
110
114
  trace = app.extensions.get("splent_config_trace", {})
111
115
  injected_keys = set(trace.keys())
@@ -123,7 +127,9 @@ def _check_env_vars(workspace, product_path, features, counters):
123
127
  col_feat = 25
124
128
  col_src = 14
125
129
 
126
- click.echo(f" {'Variable':<{col_var}} {'Feature(s)':<{col_feat}} {'Source':<{col_src}} Status")
130
+ click.echo(
131
+ f" {'Variable':<{col_var}} {'Feature(s)':<{col_feat}} {'Source':<{col_src}} Status"
132
+ )
127
133
  click.echo(f" {'-' * col_var} {'-' * col_feat} {'-' * col_src} {'-' * 10}")
128
134
 
129
135
  has_missing = False
@@ -142,7 +148,9 @@ def _check_env_vars(workspace, product_path, features, counters):
142
148
  has_missing = True
143
149
  counters["fail"] += 1
144
150
 
145
- click.echo(f" {var:<{col_var}} {feats:<{col_feat}} {src:<{col_src}} {status}")
151
+ click.echo(
152
+ f" {var:<{col_var}} {feats:<{col_feat}} {src:<{col_src}} {status}"
153
+ )
146
154
 
147
155
  if not has_missing:
148
156
  counters["ok"] += 1
@@ -178,12 +186,16 @@ def _check_symlinks(product_path, features, counters):
178
186
  feat_label += f"@{version}"
179
187
 
180
188
  if os.path.islink(link) and not os.path.exists(link):
181
- click.echo(f" {feat_label:<{col_feat}} {click.style('✖ broken', fg='red')}")
189
+ click.echo(
190
+ f" {feat_label:<{col_feat}} {click.style('✖ broken', fg='red')}"
191
+ )
182
192
  broken_count += 1
183
193
  elif os.path.exists(link):
184
194
  click.echo(f" {feat_label:<{col_feat}} {click.style('✔', fg='green')}")
185
195
  else:
186
- click.echo(f" {feat_label:<{col_feat}} {click.style('— not linked', fg='bright_black')}")
196
+ click.echo(
197
+ f" {feat_label:<{col_feat}} {click.style('— not linked', fg='bright_black')}"
198
+ )
187
199
 
188
200
  if broken_count:
189
201
  counters["fail"] += broken_count
@@ -202,6 +214,7 @@ def _check_config_overwrites(counters):
202
214
 
203
215
  try:
204
216
  from splent_cli.utils.dynamic_imports import get_app
217
+
205
218
  app = get_app()
206
219
  except Exception:
207
220
  click.echo(click.style(" ⚠ Could not boot app — skipping", fg="yellow"))
@@ -212,7 +225,7 @@ def _check_config_overwrites(counters):
212
225
  overwrites = {k: v for k, v in trace.items() if v.get("action") == "overwritten"}
213
226
 
214
227
  if not overwrites:
215
- click.echo(f" No config key overwrites detected.")
228
+ click.echo(" No config key overwrites detected.")
216
229
  counters["ok"] += 1
217
230
  else:
218
231
  col_key = 25
@@ -247,6 +260,7 @@ def _check_blueprints(counters):
247
260
 
248
261
  try:
249
262
  from splent_cli.utils.dynamic_imports import get_app
263
+
250
264
  app = get_app()
251
265
  except Exception:
252
266
  click.echo(click.style(" ⚠ Could not boot app — skipping", fg="yellow"))
@@ -304,6 +318,7 @@ def check_product():
304
318
 
305
319
  # Check for stale contracts before reading them
306
320
  from splent_cli.utils.contract_freshness import check_and_refresh_contracts
321
+
307
322
  check_and_refresh_contracts(workspace, features)
308
323
 
309
324
  _check_env_vars(workspace, product_path, features, counters)
@@ -1,9 +1,7 @@
1
1
  import click
2
2
  import shutil
3
- import os
4
3
  from pathlib import Path
5
4
 
6
- from splent_cli.utils.path_utils import PathUtils
7
5
  from splent_cli.services import context
8
6
 
9
7
 
@@ -47,7 +45,10 @@ def clean_build_artifacts(target_path: str | Path, *, quiet: bool = False):
47
45
  pass
48
46
 
49
47
  if not quiet:
50
- click.secho(f" Cleared build artifacts ({removed} __pycache__ dirs removed).", fg="green")
48
+ click.secho(
49
+ f" Cleared build artifacts ({removed} __pycache__ dirs removed).",
50
+ fg="green",
51
+ )
51
52
 
52
53
 
53
54
  @click.command(
@@ -55,9 +56,7 @@ def clean_build_artifacts(target_path: str | Path, *, quiet: bool = False):
55
56
  short_help="Clear __pycache__, .pytest_cache and build artifacts from the workspace.",
56
57
  )
57
58
  def clear_cache():
58
- if not click.confirm(
59
- "Are you sure you want to clear caches and build artifacts?"
60
- ):
59
+ if not click.confirm("Are you sure you want to clear caches and build artifacts?"):
61
60
  click.secho(" Cancelled.", fg="yellow")
62
61
  return
63
62
 
@@ -65,9 +65,7 @@ def db_dump(filename):
65
65
  click.echo(click.style(f"Error creating database dump: {e}", fg="red"))
66
66
  if os.path.exists(filename):
67
67
  os.remove(filename)
68
- click.echo(
69
- click.style(f"Partial file removed: {filename}", fg="yellow")
70
- )
68
+ click.echo(click.style(f"Partial file removed: {filename}", fg="yellow"))
71
69
 
72
70
 
73
71
  cli_command = db_dump
@@ -28,7 +28,9 @@ def _find_dependents(feature: str, product_dir: str) -> list[str]:
28
28
  uvl_path = None
29
29
  spl_name = reader.splent_config.get("spl")
30
30
  if spl_name:
31
- candidate = os.path.join(workspace, "splent_catalog", spl_name, f"{spl_name}.uvl")
31
+ candidate = os.path.join(
32
+ workspace, "splent_catalog", spl_name, f"{spl_name}.uvl"
33
+ )
32
34
  if os.path.isfile(candidate):
33
35
  uvl_path = candidate
34
36
  if not uvl_path:
@@ -70,9 +72,7 @@ def _find_dependents(feature: str, product_dir: str) -> list[str]:
70
72
  @click.option(
71
73
  "--steps", default=1, show_default=True, help="Number of migrations to roll back."
72
74
  )
73
- @click.option(
74
- "--cascade", is_flag=True, help="Also rollback dependent features."
75
- )
75
+ @click.option("--cascade", is_flag=True, help="Also rollback dependent features.")
76
76
  @context.requires_product
77
77
  def db_rollback(feature, steps, cascade):
78
78
  app = current_app
@@ -98,18 +98,25 @@ def db_rollback(feature, steps, cascade):
98
98
  f" ⚠️ Feature '{feature}' is not declared but has a DB entry (orphan).",
99
99
  fg="yellow",
100
100
  )
101
- if not click.confirm(" Remove the orphan entry from splent_migrations?", default=False):
101
+ if not click.confirm(
102
+ " Remove the orphan entry from splent_migrations?", default=False
103
+ ):
102
104
  click.echo(" ❎ Cancelled.")
103
105
  raise SystemExit(1)
104
106
  MigrationManager.delete_feature_status(app, feature)
105
107
  click.secho(f" ✅ Removed '{feature}' from splent_migrations.", fg="green")
106
108
  return
107
109
  else:
108
- click.secho(f"❌ Feature '{feature}' is not declared in this product.", fg="red")
110
+ click.secho(
111
+ f"❌ Feature '{feature}' is not declared in this product.", fg="red"
112
+ )
109
113
  raise SystemExit(1)
110
114
 
111
115
  if not mdir or not os.path.isdir(mdir):
112
- click.secho(f" ℹ️ Feature '{feature}' has no migrations — nothing to roll back.", fg="yellow")
116
+ click.secho(
117
+ f" ℹ️ Feature '{feature}' has no migrations — nothing to roll back.",
118
+ fg="yellow",
119
+ )
113
120
  return
114
121
 
115
122
  # Check for dependent features
@@ -159,8 +166,13 @@ def db_rollback(feature, steps, cascade):
159
166
  if name == dep:
160
167
  target = "installed" if dep_rev is None else "migrated"
161
168
  advance_state(
162
- product_path, product_name, key,
163
- to=target, namespace=ns, name=name, version=version,
169
+ product_path,
170
+ product_name,
171
+ key,
172
+ to=target,
173
+ namespace=ns,
174
+ name=name,
175
+ version=version,
164
176
  )
165
177
  break
166
178
  except Exception as e:
@@ -184,8 +196,13 @@ def db_rollback(feature, steps, cascade):
184
196
  if name == feature:
185
197
  target = "installed" if revision is None else "migrated"
186
198
  advance_state(
187
- product_path, product_name, key,
188
- to=target, namespace=ns, name=name, version=version,
199
+ product_path,
200
+ product_name,
201
+ key,
202
+ to=target,
203
+ namespace=ns,
204
+ name=name,
205
+ version=version,
189
206
  )
190
207
  break
191
208
  except Exception as e:
@@ -5,7 +5,10 @@ import click
5
5
 
6
6
  from splent_cli.utils.decorators import requires_db
7
7
  from splent_cli.services import context
8
- from splent_cli.utils.feature_utils import get_features_from_pyproject, normalize_namespace
8
+ from splent_cli.utils.feature_utils import (
9
+ get_features_from_pyproject,
10
+ normalize_namespace,
11
+ )
9
12
  from splent_framework.seeders.BaseSeeder import BaseSeeder
10
13
  from splent_framework.managers.feature_order import FeatureLoadOrderResolver
11
14
  from splent_framework.utils.pyproject_reader import PyprojectReader
@@ -26,7 +29,9 @@ def _resolve_feature_order(features_raw: list[str]) -> list[str]:
26
29
  reader = PyprojectReader.for_product(product_dir)
27
30
  spl_name = reader.splent_config.get("spl")
28
31
  if spl_name:
29
- candidate = os.path.join(working_dir, "splent_catalog", spl_name, f"{spl_name}.uvl")
32
+ candidate = os.path.join(
33
+ working_dir, "splent_catalog", spl_name, f"{spl_name}.uvl"
34
+ )
30
35
  if os.path.isfile(candidate):
31
36
  uvl_path = candidate
32
37
  if not uvl_path:
@@ -67,6 +67,7 @@ def db_status():
67
67
  declared_features = set(dirs.keys())
68
68
  try:
69
69
  from splent_framework.utils.pyproject_reader import PyprojectReader
70
+
70
71
  product_dir = os.path.join(str(context.workspace()), context.require_app())
71
72
  reader = PyprojectReader.for_product(product_dir)
72
73
  env = os.getenv("SPLENT_ENV")
@@ -803,6 +803,7 @@ def export_puml(
803
803
  # Check for stale contracts
804
804
  from splent_cli.utils.contract_freshness import check_and_refresh_contracts
805
805
  from splent_cli.utils.feature_utils import load_product_features
806
+
806
807
  try:
807
808
  features_raw = load_product_features(product_dir, os.getenv("SPLENT_ENV"))
808
809
  check_and_refresh_contracts(workspace, features_raw)
@@ -841,9 +842,7 @@ def export_puml(
841
842
  if not os.path.isdir(src_root):
842
843
  continue
843
844
  for org_dir in os.listdir(src_root):
844
- models_path = os.path.join(
845
- src_root, org_dir, package, "models.py"
846
- )
845
+ models_path = os.path.join(src_root, org_dir, package, "models.py")
847
846
  if os.path.isfile(models_path):
848
847
  parsed = _parse_models(models_path)
849
848
  if parsed:
@@ -12,8 +12,18 @@ from splent_cli.utils.manifest import feature_key, set_feature_state
12
12
  short_help="Adds a local (non-versioned) feature to the active product.",
13
13
  )
14
14
  @click.argument("full_name", required=True)
15
- @click.option("--dev", "env_scope", flag_value="dev", help="Add to features_dev (development only).")
16
- @click.option("--prod", "env_scope", flag_value="prod", help="Add to features_prod (production only).")
15
+ @click.option(
16
+ "--dev",
17
+ "env_scope",
18
+ flag_value="dev",
19
+ help="Add to features_dev (development only).",
20
+ )
21
+ @click.option(
22
+ "--prod",
23
+ "env_scope",
24
+ flag_value="prod",
25
+ help="Add to features_prod (production only).",
26
+ )
17
27
  def feature_add(full_name, env_scope):
18
28
  """
19
29
  Adds a local feature (no version, no repo) to the current SPLENT product.
@@ -66,8 +76,10 @@ def feature_add(full_name, env_scope):
66
76
  )
67
77
 
68
78
  features_key = f"features_{env_scope}" if env_scope else "features"
69
- features = read_features_from_data(data) if not env_scope else (
70
- data.get("tool", {}).get("splent", {}).get(features_key, [])
79
+ features = (
80
+ read_features_from_data(data)
81
+ if not env_scope
82
+ else (data.get("tool", {}).get("splent", {}).get(features_key, []))
71
83
  )
72
84
 
73
85
  if full_name not in features:
@@ -12,8 +12,18 @@ from splent_cli.utils.manifest import feature_key, set_feature_state
12
12
  )
13
13
  @click.argument("feature_identifier", required=True)
14
14
  @click.argument("version", required=True)
15
- @click.option("--dev", "env_scope", flag_value="dev", help="Add to features_dev (development only).")
16
- @click.option("--prod", "env_scope", flag_value="prod", help="Add to features_prod (production only).")
15
+ @click.option(
16
+ "--dev",
17
+ "env_scope",
18
+ flag_value="dev",
19
+ help="Add to features_dev (development only).",
20
+ )
21
+ @click.option(
22
+ "--prod",
23
+ "env_scope",
24
+ flag_value="prod",
25
+ help="Add to features_prod (production only).",
26
+ )
17
27
  def feature_attach(feature_identifier, version, env_scope):
18
28
  """
19
29
  Attach a cached feature version to the current product.
@@ -65,8 +75,10 @@ def feature_attach(feature_identifier, version, env_scope):
65
75
  )
66
76
 
67
77
  features_key = f"features_{env_scope}" if env_scope else "features"
68
- features = read_features_from_data(data) if not env_scope else (
69
- data.get("tool", {}).get("splent", {}).get(features_key, [])
78
+ features = (
79
+ read_features_from_data(data)
80
+ if not env_scope
81
+ else (data.get("tool", {}).get("splent", {}).get(features_key, []))
70
82
  )
71
83
 
72
84
  if full_name in features:
@@ -30,7 +30,9 @@ def _get_latest_tag(namespace, repo) -> str | None:
30
30
  name = tag.get("name", "")
31
31
  m = re.match(r"v?(\d+)\.(\d+)\.(\d+)", name)
32
32
  if m:
33
- versions.append((int(m.group(1)), int(m.group(2)), int(m.group(3)), name))
33
+ versions.append(
34
+ (int(m.group(1)), int(m.group(2)), int(m.group(3)), name)
35
+ )
34
36
  if not versions:
35
37
  return tags[0]["name"]
36
38
  versions.sort(reverse=True)
@@ -45,6 +47,7 @@ def _build_repo_url(namespace, repo):
45
47
  Returns a tuple (real_url, display_url) where display_url never contains a token.
46
48
  """
47
49
  from splent_cli.utils.git_url import build_git_url
50
+
48
51
  return build_git_url(namespace, repo)
49
52
 
50
53
 
@@ -67,8 +70,10 @@ def _parse_full_name(full_name: str):
67
70
 
68
71
 
69
72
  def _validate_identifier_part(value: str, label: str):
70
- if not re.fullmatch(r'[a-zA-Z0-9_\-\.]+', value):
71
- raise SystemExit(f"❌ Invalid {label}: '{value}'. Only letters, digits, - _ . allowed.")
73
+ if not re.fullmatch(r"[a-zA-Z0-9_\-\.]+", value):
74
+ raise SystemExit(
75
+ f"❌ Invalid {label}: '{value}'. Only letters, digits, - _ . allowed."
76
+ )
72
77
 
73
78
 
74
79
  # =====================================================================
@@ -148,6 +153,7 @@ def feature_clone(full_name):
148
153
  )
149
154
  except subprocess.CalledProcessError:
150
155
  import shutil
156
+
151
157
  shutil.rmtree(local_path, ignore_errors=True)
152
158
  click.secho(
153
159
  f"⚠️ Version '{version}' not found. Cloning main instead.", fg="yellow"
@@ -291,8 +291,13 @@ def _check_config_py(feature_path, ns, name, inferred):
291
291
  f" ⚠ config.py not found — {len(env_vars)} env var(s) detected but not injected into app.config.",
292
292
  fg="yellow",
293
293
  )
294
- if click.confirm(" Run feature:inject-config to generate it?", default=True):
295
- from splent_cli.commands.feature.feature_inject_config import feature_inject_config
294
+ if click.confirm(
295
+ " Run feature:inject-config to generate it?", default=True
296
+ ):
297
+ from splent_cli.commands.feature.feature_inject_config import (
298
+ feature_inject_config,
299
+ )
300
+
296
301
  ctx = click.get_current_context()
297
302
  ctx.invoke(feature_inject_config, feature_ref=name, dry_run=False)
298
303
  return
@@ -309,7 +314,10 @@ def _check_config_py(feature_path, ns, name, inferred):
309
314
  fg="yellow",
310
315
  )
311
316
  if click.confirm(" Run feature:inject-config to update it?", default=True):
312
- from splent_cli.commands.feature.feature_inject_config import feature_inject_config
317
+ from splent_cli.commands.feature.feature_inject_config import (
318
+ feature_inject_config,
319
+ )
320
+
313
321
  ctx = click.get_current_context()
314
322
  ctx.invoke(feature_inject_config, feature_ref=name, dry_run=False)
315
323
 
@@ -86,7 +86,7 @@ def make_feature(full_name):
86
86
  # Derive short name: splent_feature_notes → notes
87
87
  short_name = feature_name
88
88
  if short_name.startswith("splent_feature_"):
89
- short_name = short_name[len("splent_feature_"):]
89
+ short_name = short_name[len("splent_feature_") :]
90
90
 
91
91
  template_ctx = {
92
92
  "feature_name": feature_name,
@@ -540,6 +540,7 @@ def feature_diff(feature_ref_a, feature_ref_b, check_all, as_json, min_severity)
540
540
  # Check for stale contracts before reading them
541
541
  from splent_cli.utils.contract_freshness import check_and_refresh_contracts
542
542
  from splent_cli.utils.feature_utils import load_product_features
543
+
543
544
  try:
544
545
  features_raw = load_product_features(product_dir, os.getenv("SPLENT_ENV"))
545
546
  check_and_refresh_contracts(workspace, features_raw)