splent-cli 1.31.0__tar.gz → 1.33.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.
Files changed (202) hide show
  1. {splent_cli-1.31.0/src/splent_cli.egg-info → splent_cli-1.33.0}/PKG-INFO +1 -1
  2. {splent_cli-1.31.0 → splent_cli-1.33.0}/pyproject.toml +1 -1
  3. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/product/product_build.py +205 -23
  4. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/product/product_create.py +27 -0
  5. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/product/product_release.py +37 -2
  6. {splent_cli-1.31.0 → splent_cli-1.33.0/src/splent_cli.egg-info}/PKG-INFO +1 -1
  7. {splent_cli-1.31.0 → splent_cli-1.33.0}/LICENSE +0 -0
  8. {splent_cli-1.31.0 → splent_cli-1.33.0}/README.md +0 -0
  9. {splent_cli-1.31.0 → splent_cli-1.33.0}/setup.cfg +0 -0
  10. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/__init__.py +0 -0
  11. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/__main__.py +0 -0
  12. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/cli.py +0 -0
  13. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/__init__.py +0 -0
  14. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/cache/__init__.py +0 -0
  15. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/cache/cache_clear.py +0 -0
  16. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/cache/cache_orphans.py +0 -0
  17. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/cache/cache_outdated.py +0 -0
  18. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/cache/cache_prune.py +0 -0
  19. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/cache/cache_size.py +0 -0
  20. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/cache/cache_status.py +0 -0
  21. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/cache/cache_usage.py +0 -0
  22. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/cache/cache_versions.py +0 -0
  23. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/check/__init__.py +0 -0
  24. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/check/check_contracts.py +0 -0
  25. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/check/check_deps.py +0 -0
  26. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/check/check_docker.py +0 -0
  27. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/check/check_env.py +0 -0
  28. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/check/check_features.py +0 -0
  29. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/check/check_github.py +0 -0
  30. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/check/check_infra.py +0 -0
  31. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/check/check_product.py +0 -0
  32. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/check/check_pypi.py +0 -0
  33. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/check/check_pyproject.py +0 -0
  34. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/check/check_releases.py +0 -0
  35. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/clear/__init__.py +0 -0
  36. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/clear/clear_build.py +0 -0
  37. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/clear/clear_log.py +0 -0
  38. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/clear/clear_uploads.py +0 -0
  39. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/command/__init__.py +0 -0
  40. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/command/command_create.py +0 -0
  41. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/coverage.py +0 -0
  42. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/database/db_console.py +0 -0
  43. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/database/db_dump.py +0 -0
  44. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/database/db_migrate.py +0 -0
  45. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/database/db_reset.py +0 -0
  46. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/database/db_restore.py +0 -0
  47. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/database/db_rollback.py +0 -0
  48. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/database/db_seed.py +0 -0
  49. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/database/db_status.py +0 -0
  50. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/database/db_upgrade.py +0 -0
  51. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/doctor.py +0 -0
  52. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/env/env_list.py +0 -0
  53. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/env/env_set.py +0 -0
  54. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/env/env_show.py +0 -0
  55. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/export/__init__.py +0 -0
  56. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/export/export_puml.py +0 -0
  57. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/feature/feature_add.py +0 -0
  58. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/feature/feature_attach.py +0 -0
  59. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/feature/feature_clean.py +0 -0
  60. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/feature/feature_clone.py +0 -0
  61. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/feature/feature_compat.py +0 -0
  62. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/feature/feature_compile.py +0 -0
  63. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/feature/feature_contract.py +0 -0
  64. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/feature/feature_create.py +0 -0
  65. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/feature/feature_delete.py +0 -0
  66. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/feature/feature_detach.py +0 -0
  67. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/feature/feature_discard.py +0 -0
  68. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/feature/feature_drift.py +0 -0
  69. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/feature/feature_env.py +0 -0
  70. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/feature/feature_fork.py +0 -0
  71. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/feature/feature_git.py +0 -0
  72. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/feature/feature_hook_add.py +0 -0
  73. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/feature/feature_hook_remove.py +0 -0
  74. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/feature/feature_hooks.py +0 -0
  75. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/feature/feature_impact.py +0 -0
  76. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/feature/feature_info.py +0 -0
  77. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/feature/feature_inject_config.py +0 -0
  78. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/feature/feature_install.py +0 -0
  79. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/feature/feature_list.py +0 -0
  80. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/feature/feature_order.py +0 -0
  81. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/feature/feature_outdated.py +0 -0
  82. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/feature/feature_pin.py +0 -0
  83. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/feature/feature_pip_install.py +0 -0
  84. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/feature/feature_pull.py +0 -0
  85. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/feature/feature_refine.py +0 -0
  86. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/feature/feature_release.py +0 -0
  87. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/feature/feature_remove.py +0 -0
  88. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/feature/feature_rename.py +0 -0
  89. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/feature/feature_search.py +0 -0
  90. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/feature/feature_status.py +0 -0
  91. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/feature/feature_sync_template.py +0 -0
  92. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/feature/feature_test.py +0 -0
  93. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/feature/feature_translate.py +0 -0
  94. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/feature/feature_unlock.py +0 -0
  95. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/feature/feature_upgrade.py +0 -0
  96. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/feature/feature_versions.py +0 -0
  97. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/feature/feature_xray.py +0 -0
  98. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/lint.py +0 -0
  99. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/locust.py +0 -0
  100. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/marketplace/login.py +0 -0
  101. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/marketplace/logout.py +0 -0
  102. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/marketplace/marketplace_auth_utils.py +0 -0
  103. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/marketplace/marketplace_index.py +0 -0
  104. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/marketplace/whoami.py +0 -0
  105. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/product/__init__.py +0 -0
  106. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/product/product_auto_require.py +0 -0
  107. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/product/product_clean.py +0 -0
  108. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/product/product_commands.py +0 -0
  109. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/product/product_config.py +0 -0
  110. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/product/product_configure.py +0 -0
  111. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/product/product_console.py +0 -0
  112. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/product/product_containers.py +0 -0
  113. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/product/product_deploy.py +0 -0
  114. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/product/product_derive.py +0 -0
  115. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/product/product_deselect.py +0 -0
  116. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/product/product_down.py +0 -0
  117. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/product/product_drift.py +0 -0
  118. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/product/product_env.py +0 -0
  119. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/product/product_list.py +0 -0
  120. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/product/product_logs.py +0 -0
  121. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/product/product_missing.py +0 -0
  122. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/product/product_port.py +0 -0
  123. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/product/product_resolve.py +0 -0
  124. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/product/product_restart.py +0 -0
  125. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/product/product_routes.py +0 -0
  126. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/product/product_run.py +0 -0
  127. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/product/product_select.py +0 -0
  128. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/product/product_shell.py +0 -0
  129. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/product/product_signals.py +0 -0
  130. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/product/product_sync_template.py +0 -0
  131. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/product/product_test.py +0 -0
  132. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/product/product_up.py +0 -0
  133. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/product/product_validate.py +0 -0
  134. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/release/__init__.py +0 -0
  135. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/release/release_core.py +0 -0
  136. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/release/release_resume.py +0 -0
  137. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/selenium.py +0 -0
  138. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/spl/__init__.py +0 -0
  139. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/spl/spl_add_constraints.py +0 -0
  140. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/spl/spl_add_feature.py +0 -0
  141. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/spl/spl_compare.py +0 -0
  142. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/spl/spl_configurations.py +0 -0
  143. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/spl/spl_create.py +0 -0
  144. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/spl/spl_deps.py +0 -0
  145. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/spl/spl_features.py +0 -0
  146. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/spl/spl_fetch.py +0 -0
  147. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/spl/spl_info.py +0 -0
  148. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/spl/spl_list.py +0 -0
  149. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/spl/spl_outdated.py +0 -0
  150. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/spl/spl_pin.py +0 -0
  151. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/spl/spl_publish.py +0 -0
  152. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/spl/spl_remove_feature.py +0 -0
  153. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/spl/spl_utils.py +0 -0
  154. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/tokens_setup.py +0 -0
  155. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/uvl/uvl_utils.py +0 -0
  156. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/commands/version.py +0 -0
  157. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/services/__init__.py +0 -0
  158. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/services/compose.py +0 -0
  159. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/services/context.py +0 -0
  160. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/services/credentials.py +0 -0
  161. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/services/deploy_bundle.py +0 -0
  162. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/services/image_registry.py +0 -0
  163. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/services/index_refresh.py +0 -0
  164. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/services/marketplace.py +0 -0
  165. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/services/marketplace_api.py +0 -0
  166. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/services/marketplace_url.py +0 -0
  167. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/services/preflight.py +0 -0
  168. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/services/pypi_quota.py +0 -0
  169. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/services/registry.py +0 -0
  170. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/services/release.py +0 -0
  171. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/services/release_dry_run.py +0 -0
  172. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/services/release_gate.py +0 -0
  173. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/services/spl_store.py +0 -0
  174. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/utils/__init__.py +0 -0
  175. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/utils/archetype.py +0 -0
  176. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/utils/cache_utils.py +0 -0
  177. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/utils/command_loader.py +0 -0
  178. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/utils/contract_freshness.py +0 -0
  179. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/utils/db_client.py +0 -0
  180. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/utils/db_utils.py +0 -0
  181. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/utils/decorators.py +0 -0
  182. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/utils/dynamic_imports.py +0 -0
  183. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/utils/feature_installer.py +0 -0
  184. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/utils/feature_utils.py +0 -0
  185. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/utils/forge.py +0 -0
  186. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/utils/git_url.py +0 -0
  187. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/utils/integrity.py +0 -0
  188. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/utils/io_utils.py +0 -0
  189. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/utils/lifecycle.py +0 -0
  190. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/utils/manifest.py +0 -0
  191. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/utils/path_utils.py +0 -0
  192. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/utils/proc.py +0 -0
  193. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/utils/redact.py +0 -0
  194. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/utils/refinement_facts.py +0 -0
  195. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/utils/template_drift.py +0 -0
  196. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/utils/toml_edit.py +0 -0
  197. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli/utils/upgrade_plan.py +0 -0
  198. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli.egg-info/SOURCES.txt +0 -0
  199. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli.egg-info/dependency_links.txt +0 -0
  200. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli.egg-info/entry_points.txt +0 -0
  201. {splent_cli-1.31.0 → splent_cli-1.33.0}/src/splent_cli.egg-info/requires.txt +0 -0
  202. {splent_cli-1.31.0 → splent_cli-1.33.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.31.0
3
+ Version: 1.33.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
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "splent_cli"
7
- version = "1.31.0"
7
+ version = "1.33.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"
@@ -38,12 +38,34 @@ USER_TUNABLE_MARKER = "user-tunable"
38
38
  CONTRACTS_SNAPSHOT = "splent.contracts.json"
39
39
  CONTRACTS_FORMAT = 1
40
40
 
41
- # The framework, the CLI and the WSGI server the production image installs,
42
- # pinned. Written by product:build into docker/, read by the production
43
- # Dockerfile, versioned with the product, so a clone builds the image a release
44
- # published.
45
- REQUIREMENTS_FILE = "requirements.prod.txt"
46
- GUNICORN_REQUIREMENT = "gunicorn>=23,<24"
41
+ # What the production image installs besides the features, in the product's
42
+ # pyproject.toml beside the feature pins, where pip does not read it: the
43
+ # framework and the CLI as [project] dependencies would replace the editable
44
+ # workspace checkouts development runs on. product:build keeps the framework
45
+ # and the CLI at the versions the product is built with; the production
46
+ # Dockerfile reads the table with tomllib. A bare version means exactly that
47
+ # version, anything else is a pip specifier.
48
+ RUNTIME_TABLE = ("tool", "splent", "runtime")
49
+ RUNTIME_DEFAULTS = {"gunicorn": ">=23,<24"}
50
+ RUNTIME_COMMENT = (
51
+ "# What the production image installs besides the features. splent\n"
52
+ "# product:build keeps splent_framework and splent_cli at the versions this\n"
53
+ "# product is built with; a bare version means exactly that version.\n"
54
+ )
55
+ # Where those pins lived before, in a file of their own. Removed by the build
56
+ # that moves them into pyproject.toml.
57
+ LEGACY_REQUIREMENTS_FILE = "requirements.prod.txt"
58
+
59
+ # Every third-party package the production image installs, at the version the
60
+ # last build resolved, read back from the image with pip freeze. The
61
+ # Dockerfile applies it as a constraint on every pip install, so two builds of
62
+ # one commit install the same set. Versioned in docker/.
63
+ LOCK_FILE = "requirements.lock"
64
+ LOCK_HEADER = (
65
+ "# Every third-party package the production image installs, at the version\n"
66
+ "# the last build resolved. Written by splent product:build and\n"
67
+ "# product:release from the image itself. Do not edit it.\n"
68
+ )
47
69
 
48
70
  # Database settings every product names the same way. A template writes <SET>
49
71
  # for them, and the CLI fills them in rather than ask: nobody needs to choose
@@ -412,16 +434,112 @@ def runtime_pins(workspace: str) -> dict:
412
434
  }
413
435
 
414
436
 
415
- def runtime_requirements(workspace: str) -> str:
416
- """The text of docker/requirements.prod.txt."""
417
- pins = runtime_pins(workspace)
418
- return (
419
- "# What the production image installs from PyPI besides the features,\n"
420
- "# which pyproject.toml pins. Written by splent product:build from the\n"
421
- "# framework and the CLI this product was built with. Do not edit it.\n"
422
- + "".join(f"{name}=={version}\n" for name, version in pins.items())
423
- + f"{GUNICORN_REQUIREMENT}\n"
437
+ def runtime_requirement(name: str, spec: str) -> str:
438
+ """One entry of [tool.splent.runtime] as a pip requirement."""
439
+ spec = str(spec).strip()
440
+ return f"{name}=={spec}" if spec[:1].isdigit() else f"{name}{spec}"
441
+
442
+
443
+ def write_runtime_pins(pyproject_path: str, workspace: str) -> dict | None:
444
+ """Keep [tool.splent.runtime] at the framework and CLI of this build.
445
+
446
+ Other entries (gunicorn, anything the product added) are left as they are,
447
+ and the file is only written when something changes, through the editor
448
+ that keeps comments and layout. Returns the table when it changed.
449
+ """
450
+ from splent_cli.utils.toml_edit import edit_toml
451
+
452
+ with open(pyproject_path, encoding="utf-8", newline="") as fh:
453
+ text = fh.read()
454
+ data = load_toml(pyproject_path, what="pyproject.toml")
455
+ splent = data.setdefault("tool", {}).setdefault("splent", {})
456
+ current = dict(splent.get("runtime") or {})
457
+ # The framework and the CLI first, where a reader of a new table looks.
458
+ wanted = dict(runtime_pins(workspace))
459
+ for name, spec in {**RUNTIME_DEFAULTS, **current}.items():
460
+ wanted.setdefault(name, spec)
461
+ if wanted == current:
462
+ return None
463
+ splent["runtime"] = wanted
464
+ result = edit_toml(text, data)
465
+ header = "[" + ".".join(RUNTIME_TABLE) + "]"
466
+ lines = result.splitlines(keepends=True)
467
+ for i, line in enumerate(lines):
468
+ if line.strip() == header and not (i and lines[i - 1].lstrip().startswith("#")):
469
+ newline = "\r\n" if line.endswith("\r\n") else "\n"
470
+ lines[i:i] = [c + newline for c in RUNTIME_COMMENT.splitlines()]
471
+ break
472
+ atomic_write(pyproject_path, "".join(lines), newline="")
473
+ return wanted
474
+
475
+
476
+ def _canonical(name: str) -> str:
477
+ import re
478
+
479
+ return re.sub(r"[-_.]+", "-", name).lower()
480
+
481
+
482
+ def lock_text(freeze_output: str, product: str) -> str:
483
+ """docker/requirements.lock from what pip freeze reports in the image.
484
+
485
+ SPLENT's own packages (the framework, the CLI, every feature) and the
486
+ product are left out: their versions are pinned where they are chosen, in
487
+ pyproject.toml, and a feature installed from its git tag is not something
488
+ a constraints file can name.
489
+ """
490
+ product_name = _canonical(product)
491
+ kept = []
492
+ for line in freeze_output.splitlines():
493
+ line = line.strip()
494
+ if not line or line.startswith(("#", "-")) or " @ " in line or "==" not in line:
495
+ continue
496
+ name = _canonical(line.split("==", 1)[0])
497
+ if name.startswith("splent") or name == product_name:
498
+ continue
499
+ kept.append(line)
500
+ return LOCK_HEADER + "".join(f"{line}\n" for line in sorted(kept, key=str.lower))
501
+
502
+
503
+ def ensure_lock(docker_path: str) -> str:
504
+ """The lock's path, written with no pin yet when the product has none."""
505
+ path = os.path.join(docker_path, LOCK_FILE)
506
+ if not os.path.isfile(path):
507
+ atomic_write(path, LOCK_HEADER, dir_owner=True)
508
+ return path
509
+
510
+
511
+ def write_lock_from_image(image: str, product: str, docker_path: str) -> int:
512
+ """Pin in docker/requirements.lock what ``image`` installed. Returns how many."""
513
+ frozen = subprocess.run(
514
+ ["docker", "run", "--rm", "--entrypoint", "pip", image, "freeze"],
515
+ capture_output=True,
516
+ text=True,
517
+ check=True,
518
+ ).stdout
519
+ text = lock_text(frozen, product)
520
+ atomic_write(os.path.join(docker_path, LOCK_FILE), text, dir_owner=True)
521
+ return sum(1 for line in text.splitlines() if line and not line.startswith("#"))
522
+
523
+
524
+ def resolve_lock(product: str, workspace: str, docker_path: str) -> int:
525
+ """Resolve the third-party packages afresh and pin them in the lock.
526
+
527
+ Builds the image's build stage with SPLENT_FRESH_LOCK=1, which leaves the
528
+ current lock out, and reads back what it installed. product:release runs
529
+ this before its commit, so the lock it commits is what its image installs.
530
+ """
531
+ tag = f"{product}:lock"
532
+ subprocess.run(
533
+ production_image_build_command(
534
+ product,
535
+ workspace,
536
+ docker_path,
537
+ [tag],
538
+ extra=("--target", "builder", "--build-arg", "SPLENT_FRESH_LOCK=1"),
539
+ ),
540
+ check=True,
424
541
  )
542
+ return write_lock_from_image(tag, product, docker_path)
425
543
 
426
544
 
427
545
  def pypi_serves(package: str, version: str) -> bool | None:
@@ -454,6 +572,35 @@ def production_dockerfile(product: str, docker_path: str) -> str:
454
572
  return os.path.join(docker_path, f"Dockerfile.{product}.prod")
455
573
 
456
574
 
575
+ # What a production Dockerfile from an older CLI does that this one cannot
576
+ # feed, each with what it says about it.
577
+ STALE_DOCKERFILE_MARKERS = (
578
+ (
579
+ "COPY splent_framework",
580
+ "copies splent_framework/ from the workspace, which the product's own "
581
+ "build context does not have",
582
+ ),
583
+ (
584
+ LEGACY_REQUIREMENTS_FILE,
585
+ f"installs docker/{LEGACY_REQUIREMENTS_FILE}, which [tool.splent.runtime] "
586
+ "in pyproject.toml replaces",
587
+ ),
588
+ )
589
+
590
+
591
+ def stale_dockerfile(dockerfile: str) -> str | None:
592
+ """Why the production Dockerfile predates this CLI, or None when it does not."""
593
+ try:
594
+ with open(dockerfile, encoding="utf-8") as fh:
595
+ text = fh.read()
596
+ except OSError:
597
+ return None
598
+ for marker, why in STALE_DOCKERFILE_MARKERS:
599
+ if marker in text:
600
+ return why
601
+ return None
602
+
603
+
457
604
  def forge_build_args() -> list[str]:
458
605
  """``--build-arg`` pairs for the forge settings that are set."""
459
606
  args: list[str] = []
@@ -470,6 +617,7 @@ def production_image_build_command(
470
617
  docker_path: str,
471
618
  tags: Sequence[str],
472
619
  context: str | None = None,
620
+ extra: Sequence[str] = (),
473
621
  ) -> list[str]:
474
622
  """The ``docker build`` that produces the product's production image.
475
623
 
@@ -489,6 +637,7 @@ def production_image_build_command(
489
637
  for tag in tags:
490
638
  cmd += ["-t", tag]
491
639
  cmd += forge_build_args()
640
+ cmd += list(extra)
492
641
  cmd += ["-f", dockerfile, context]
493
642
  return cmd
494
643
 
@@ -526,6 +675,7 @@ def build_production_image(
526
675
  *,
527
676
  stage_model: bool = True,
528
677
  committed: bool = False,
678
+ fresh_lock: bool = False,
529
679
  ) -> None:
530
680
  """Build the production image under ``tags``.
531
681
 
@@ -547,9 +697,12 @@ def build_production_image(
547
697
  staged = stage_spl_model(workspace, product, docker_path)
548
698
  if staged:
549
699
  click.echo(f" Staged the UVL model: {staged}")
700
+ extra = ("--build-arg", "SPLENT_FRESH_LOCK=1") if fresh_lock else ()
550
701
  if not committed:
551
702
  subprocess.run(
552
- production_image_build_command(product, workspace, docker_path, tags),
703
+ production_image_build_command(
704
+ product, workspace, docker_path, tags, extra=extra
705
+ ),
553
706
  check=True,
554
707
  )
555
708
  return
@@ -557,7 +710,7 @@ def build_production_image(
557
710
  export_commit(os.path.join(workspace, product), tree)
558
711
  subprocess.run(
559
712
  production_image_build_command(
560
- product, workspace, docker_path, tags, context=tree
713
+ product, workspace, docker_path, tags, context=tree, extra=extra
561
714
  ),
562
715
  check=True,
563
716
  )
@@ -1301,8 +1454,8 @@ def write_deploy_artifacts(
1301
1454
 
1302
1455
  * ``deploy/``, the bundle a host runs with docker compose alone (see
1303
1456
  :mod:`splent_cli.services.deploy_bundle`);
1304
- * ``docker/requirements.prod.txt``, the framework and CLI the image
1305
- installs from PyPI;
1457
+ * ``[tool.splent.runtime]`` in pyproject.toml, the framework and CLI the
1458
+ image installs from PyPI;
1306
1459
  * ``splent.contracts.json`` and ``docker/spl/``, the refinement metadata
1307
1460
  and the UVL model the image reads.
1308
1461
 
@@ -1568,10 +1721,23 @@ def write_deploy_artifacts(
1568
1721
  # ---------------------------------------------------------
1569
1722
  # 4) What the image installs and reads, pinned
1570
1723
  # ---------------------------------------------------------
1571
- requirements_path = os.path.join(docker_path, REQUIREMENTS_FILE)
1572
- atomic_write(requirements_path, runtime_requirements(workspace), dir_owner=True)
1573
- written.append(f"docker/{REQUIREMENTS_FILE}")
1574
- click.echo(f"✅ Created: {requirements_path}")
1724
+ pins = write_runtime_pins(pyproject_path, workspace)
1725
+ written.append("pyproject.toml")
1726
+ if pins:
1727
+ click.echo(
1728
+ "✅ Pinned "
1729
+ + ", ".join(f"{name} {spec}" for name, spec in pins.items())
1730
+ + " in pyproject.toml [tool.splent.runtime]"
1731
+ )
1732
+ legacy_requirements = os.path.join(docker_path, LEGACY_REQUIREMENTS_FILE)
1733
+ if os.path.isfile(legacy_requirements):
1734
+ os.remove(legacy_requirements)
1735
+ click.echo(
1736
+ click.style(" removed ", dim=True)
1737
+ + f"docker/{LEGACY_REQUIREMENTS_FILE}, now [tool.splent.runtime]"
1738
+ )
1739
+ ensure_lock(docker_path)
1740
+ written.append(f"docker/{LOCK_FILE}")
1575
1741
  unpublished = unpublished_runtime_pins(workspace)
1576
1742
  if unpublished:
1577
1743
  click.secho(
@@ -1733,6 +1899,15 @@ def product_build(no_image, skip_preflight):
1733
1899
  f" Run 'splent product:sync-template' to generate it.",
1734
1900
  fg="yellow",
1735
1901
  )
1902
+ elif stale := stale_dockerfile(dockerfile):
1903
+ click.secho(
1904
+ f"\n❌ docker/{os.path.basename(dockerfile)} comes from an older "
1905
+ f"CLI, it {stale}.\n"
1906
+ f" Run 'splent product:sync-template {product} --docker' and "
1907
+ "build again.",
1908
+ fg="red",
1909
+ )
1910
+ raise SystemExit(1)
1736
1911
  else:
1737
1912
  click.echo(f"\n🐳 Building Docker image: {product}:{bundle.version}...")
1738
1913
  try:
@@ -1742,8 +1917,15 @@ def product_build(no_image, skip_preflight):
1742
1917
  docker_path,
1743
1918
  [f"{product}:{bundle.version}", f"{product}:latest"],
1744
1919
  stage_model=False,
1920
+ fresh_lock=True,
1745
1921
  )
1746
1922
  click.echo(f"✅ Image built: {product}:{bundle.version}")
1923
+ pinned = write_lock_from_image(
1924
+ f"{product}:{bundle.version}", product, docker_path
1925
+ )
1926
+ click.echo(
1927
+ f"✅ Pinned {pinned} third-party package(s) in docker/{LOCK_FILE}"
1928
+ )
1747
1929
  except subprocess.CalledProcessError:
1748
1930
  click.secho("❌ Docker image build failed.", fg="red")
1749
1931
  raise SystemExit(1)
@@ -31,6 +31,27 @@ except Exception:
31
31
  PRODUCT_NAME_RE = re.compile(r"^[a-z_][a-z0-9_]*$")
32
32
 
33
33
 
34
+ def _runtime_versions() -> tuple[str, str]:
35
+ """The framework and CLI versions a new product's image installs.
36
+
37
+ The ones product:build pins, so the first build leaves them as they are.
38
+ Empty when one cannot be read, which installs whatever PyPI serves until
39
+ that first build pins it.
40
+ """
41
+ from splent_cli.commands.product.product_build import (
42
+ cli_version,
43
+ framework_version,
44
+ )
45
+
46
+ versions = []
47
+ for read in (lambda: framework_version(str(context.workspace())), cli_version):
48
+ try:
49
+ versions.append(read())
50
+ except Exception: # noqa: BLE001 - only the default runtime pins depend on it
51
+ versions.append("")
52
+ return versions[0], versions[1]
53
+
54
+
34
55
  def validate_product_name(name: str) -> None:
35
56
  """Refuse a name that cannot be a Python package.
36
57
 
@@ -202,6 +223,7 @@ def make_product(name, spl_name, spl_doi, features_file, force):
202
223
  except Exception:
203
224
  pass
204
225
 
226
+ runtime_framework, runtime_cli = _runtime_versions()
205
227
  template_ctx = {
206
228
  "product_name": name,
207
229
  "pascal_name": pascalcase(name),
@@ -212,6 +234,11 @@ def make_product(name, spl_name, spl_doi, features_file, force):
212
234
  "mailhog_port_one": mailhog_port_one,
213
235
  "mailhog_port_two": mailhog_port_two,
214
236
  "cli_version": _CLI_VERSION,
237
+ # [tool.splent.runtime]: what the production image installs. The
238
+ # same versions product:build would write, so a new product's image
239
+ # builds before its first product:build.
240
+ "runtime_framework": runtime_framework,
241
+ "runtime_cli": runtime_cli,
215
242
  "network_name": "splent_network",
216
243
  "spl_name": spl_name or "",
217
244
  "spl_mirror": pin.mirror,
@@ -11,11 +11,13 @@ import tempfile
11
11
  import click
12
12
  from splent_cli.commands.product.product_build import (
13
13
  CONTRACTS_SNAPSHOT,
14
- REQUIREMENTS_FILE,
14
+ LOCK_FILE,
15
15
  SPL_STAGING_DIR,
16
16
  build_production_image,
17
17
  production_dockerfile,
18
18
  unpublished_runtime_pins,
19
+ resolve_lock,
20
+ stale_dockerfile,
19
21
  unresolved_pins,
20
22
  write_deploy_artifacts,
21
23
  )
@@ -123,7 +125,7 @@ RELEASE_ARTIFACTS = (
123
125
  # Directories end in "/", so git matches directory rules against them
124
126
  # before they exist.
125
127
  f"{deploy_bundle.BUNDLE_DIR}/",
126
- f"docker/{REQUIREMENTS_FILE}",
128
+ f"docker/{LOCK_FILE}",
127
129
  CONTRACTS_SNAPSHOT,
128
130
  f"docker/{SPL_STAGING_DIR}/",
129
131
  )
@@ -184,6 +186,17 @@ def _guard_deployable(workspace: str, product: str, product_path: str) -> None:
184
186
  )
185
187
  raise SystemExit(1)
186
188
 
189
+ dockerfile = production_dockerfile(product, os.path.join(product_path, "docker"))
190
+ stale = stale_dockerfile(dockerfile)
191
+ if stale:
192
+ click.secho(
193
+ f" Cannot release: docker/{os.path.basename(dockerfile)} comes from "
194
+ f"an older CLI, it {stale}. Run splent product:sync-template "
195
+ f"{product} --docker, commit it and release again.",
196
+ fg="red",
197
+ )
198
+ raise SystemExit(1)
199
+
187
200
  ignored = subprocess.run(
188
201
  ["git", "check-ignore", "--no-index", *RELEASE_ARTIFACTS],
189
202
  capture_output=True,
@@ -216,6 +229,28 @@ def write_release_artifacts(
216
229
  # The release about to publish the first image has no tag yet.
217
230
  publishes_image=publishes_image,
218
231
  )
232
+ if publishes_image:
233
+ # Resolved afresh for every release, so each one picks up the
234
+ # third-party fixes PyPI has, and committed, so a rebuild of the tag
235
+ # installs exactly what the release did.
236
+ require_docker()
237
+ click.echo(" lock resolving the third-party packages...")
238
+ try:
239
+ pinned = resolve_lock(
240
+ product, workspace, os.path.join(product_path, "docker")
241
+ )
242
+ except subprocess.CalledProcessError:
243
+ click.secho(
244
+ " error: the image's build stage did not build, so the "
245
+ "third-party packages could not be pinned. Nothing was "
246
+ "committed; the version bump in pyproject.toml is still to "
247
+ "undo or to release again.",
248
+ fg="red",
249
+ )
250
+ raise SystemExit(1)
251
+ click.echo(
252
+ f" lock {pinned} third-party package(s) pinned in docker/{LOCK_FILE}"
253
+ )
219
254
  subprocess.run(
220
255
  ["git", "add", "--", *bundle.paths],
221
256
  cwd=product_path,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: splent_cli
3
- Version: 1.31.0
3
+ Version: 1.33.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
File without changes
File without changes
File without changes