splent-cli 1.50.1__tar.gz → 1.52.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 (323) hide show
  1. {splent_cli-1.50.1/src/splent_cli.egg-info → splent_cli-1.52.0}/PKG-INFO +1 -1
  2. {splent_cli-1.50.1 → splent_cli-1.52.0}/pyproject.toml +1 -1
  3. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/product/product_release.py +29 -12
  4. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/release/release_resume.py +41 -1
  5. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/services/frontend.py +4 -0
  6. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/services/registry.py +17 -11
  7. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/services/release.py +16 -1
  8. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/services/release_gate.py +2 -2
  9. splent_cli-1.52.0/src/splent_cli/services/release_workspace.py +180 -0
  10. splent_cli-1.52.0/src/splent_cli/services/source_mirror.py +356 -0
  11. {splent_cli-1.50.1 → splent_cli-1.52.0/src/splent_cli.egg-info}/PKG-INFO +1 -1
  12. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli.egg-info/SOURCES.txt +2 -0
  13. {splent_cli-1.50.1 → splent_cli-1.52.0}/COPYING +0 -0
  14. {splent_cli-1.50.1 → splent_cli-1.52.0}/COPYING.LESSER +0 -0
  15. {splent_cli-1.50.1 → splent_cli-1.52.0}/README.md +0 -0
  16. {splent_cli-1.50.1 → splent_cli-1.52.0}/setup.cfg +0 -0
  17. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/__init__.py +0 -0
  18. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/__main__.py +0 -0
  19. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/cli.py +0 -0
  20. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/__init__.py +0 -0
  21. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/cache/__init__.py +0 -0
  22. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/cache/cache_clear.py +0 -0
  23. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/cache/cache_orphans.py +0 -0
  24. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/cache/cache_outdated.py +0 -0
  25. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/cache/cache_prune.py +0 -0
  26. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/cache/cache_size.py +0 -0
  27. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/cache/cache_status.py +0 -0
  28. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/cache/cache_usage.py +0 -0
  29. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/cache/cache_versions.py +0 -0
  30. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/check/__init__.py +0 -0
  31. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/check/check_contracts.py +0 -0
  32. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/check/check_deps.py +0 -0
  33. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/check/check_docker.py +0 -0
  34. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/check/check_env.py +0 -0
  35. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/check/check_features.py +0 -0
  36. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/check/check_github.py +0 -0
  37. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/check/check_infra.py +0 -0
  38. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/check/check_product.py +0 -0
  39. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/check/check_pypi.py +0 -0
  40. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/check/check_pyproject.py +0 -0
  41. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/check/check_releases.py +0 -0
  42. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/check/check_vendor.py +0 -0
  43. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/clear/__init__.py +0 -0
  44. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/clear/clear_build.py +0 -0
  45. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/clear/clear_log.py +0 -0
  46. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/clear/clear_uploads.py +0 -0
  47. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/command/__init__.py +0 -0
  48. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/command/command_create.py +0 -0
  49. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/coverage.py +0 -0
  50. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/database/db_console.py +0 -0
  51. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/database/db_dump.py +0 -0
  52. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/database/db_migrate.py +0 -0
  53. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/database/db_reset.py +0 -0
  54. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/database/db_restore.py +0 -0
  55. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/database/db_rollback.py +0 -0
  56. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/database/db_seed.py +0 -0
  57. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/database/db_status.py +0 -0
  58. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/database/db_upgrade.py +0 -0
  59. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/doctor.py +0 -0
  60. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/env/env_list.py +0 -0
  61. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/env/env_set.py +0 -0
  62. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/env/env_show.py +0 -0
  63. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/export/__init__.py +0 -0
  64. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/export/export_puml.py +0 -0
  65. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/feature/feature_add.py +0 -0
  66. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/feature/feature_attach.py +0 -0
  67. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/feature/feature_clean.py +0 -0
  68. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/feature/feature_clone.py +0 -0
  69. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/feature/feature_compat.py +0 -0
  70. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/feature/feature_compile.py +0 -0
  71. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/feature/feature_contract.py +0 -0
  72. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/feature/feature_create.py +0 -0
  73. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/feature/feature_delete.py +0 -0
  74. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/feature/feature_detach.py +0 -0
  75. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/feature/feature_discard.py +0 -0
  76. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/feature/feature_drift.py +0 -0
  77. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/feature/feature_env.py +0 -0
  78. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/feature/feature_fork.py +0 -0
  79. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/feature/feature_frontend_init.py +0 -0
  80. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/feature/feature_git.py +0 -0
  81. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/feature/feature_hook_add.py +0 -0
  82. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/feature/feature_hook_remove.py +0 -0
  83. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/feature/feature_hooks.py +0 -0
  84. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/feature/feature_impact.py +0 -0
  85. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/feature/feature_info.py +0 -0
  86. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/feature/feature_inject_config.py +0 -0
  87. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/feature/feature_install.py +0 -0
  88. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/feature/feature_list.py +0 -0
  89. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/feature/feature_npm.py +0 -0
  90. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/feature/feature_order.py +0 -0
  91. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/feature/feature_outdated.py +0 -0
  92. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/feature/feature_pin.py +0 -0
  93. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/feature/feature_pip_install.py +0 -0
  94. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/feature/feature_pull.py +0 -0
  95. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/feature/feature_refine.py +0 -0
  96. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/feature/feature_release.py +0 -0
  97. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/feature/feature_remove.py +0 -0
  98. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/feature/feature_rename.py +0 -0
  99. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/feature/feature_search.py +0 -0
  100. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/feature/feature_security.py +0 -0
  101. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/feature/feature_status.py +0 -0
  102. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/feature/feature_sync_template.py +0 -0
  103. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/feature/feature_test.py +0 -0
  104. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/feature/feature_translate.py +0 -0
  105. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/feature/feature_unlock.py +0 -0
  106. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/feature/feature_upgrade.py +0 -0
  107. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/feature/feature_versions.py +0 -0
  108. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/feature/feature_xray.py +0 -0
  109. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/lint.py +0 -0
  110. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/locust.py +0 -0
  111. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/marketplace/login.py +0 -0
  112. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/marketplace/logout.py +0 -0
  113. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/marketplace/marketplace_auth_utils.py +0 -0
  114. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/marketplace/marketplace_index.py +0 -0
  115. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/marketplace/whoami.py +0 -0
  116. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/product/__init__.py +0 -0
  117. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/product/product_auto_require.py +0 -0
  118. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/product/product_build.py +0 -0
  119. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/product/product_clean.py +0 -0
  120. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/product/product_commands.py +0 -0
  121. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/product/product_config.py +0 -0
  122. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/product/product_configure.py +0 -0
  123. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/product/product_console.py +0 -0
  124. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/product/product_containers.py +0 -0
  125. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/product/product_create.py +0 -0
  126. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/product/product_deploy.py +0 -0
  127. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/product/product_derive.py +0 -0
  128. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/product/product_deselect.py +0 -0
  129. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/product/product_down.py +0 -0
  130. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/product/product_drift.py +0 -0
  131. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/product/product_env.py +0 -0
  132. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/product/product_frontend_audit.py +0 -0
  133. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/product/product_list.py +0 -0
  134. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/product/product_logs.py +0 -0
  135. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/product/product_missing.py +0 -0
  136. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/product/product_params.py +0 -0
  137. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/product/product_port.py +0 -0
  138. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/product/product_resolve.py +0 -0
  139. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/product/product_restart.py +0 -0
  140. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/product/product_routes.py +0 -0
  141. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/product/product_run.py +0 -0
  142. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/product/product_select.py +0 -0
  143. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/product/product_shell.py +0 -0
  144. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/product/product_signals.py +0 -0
  145. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/product/product_sync_template.py +0 -0
  146. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/product/product_test.py +0 -0
  147. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/product/product_up.py +0 -0
  148. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/product/product_validate.py +0 -0
  149. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/release/__init__.py +0 -0
  150. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/release/release_core.py +0 -0
  151. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/selenium.py +0 -0
  152. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/spl/__init__.py +0 -0
  153. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/spl/spl_add_constraints.py +0 -0
  154. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/spl/spl_add_feature.py +0 -0
  155. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/spl/spl_compare.py +0 -0
  156. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/spl/spl_configurations.py +0 -0
  157. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/spl/spl_create.py +0 -0
  158. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/spl/spl_deps.py +0 -0
  159. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/spl/spl_features.py +0 -0
  160. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/spl/spl_fetch.py +0 -0
  161. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/spl/spl_info.py +0 -0
  162. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/spl/spl_list.py +0 -0
  163. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/spl/spl_outdated.py +0 -0
  164. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/spl/spl_pin.py +0 -0
  165. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/spl/spl_publish.py +0 -0
  166. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/spl/spl_remove_feature.py +0 -0
  167. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/spl/spl_utils.py +0 -0
  168. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/storage/__init__.py +0 -0
  169. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/storage/storage_migrate.py +0 -0
  170. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/tokens_setup.py +0 -0
  171. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/uvl/uvl_utils.py +0 -0
  172. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/commands/version.py +0 -0
  173. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/services/__init__.py +0 -0
  174. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/services/compose.py +0 -0
  175. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/services/context.py +0 -0
  176. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/services/credentials.py +0 -0
  177. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/services/deploy_bundle.py +0 -0
  178. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/services/editable_refresh.py +0 -0
  179. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/services/image_registry.py +0 -0
  180. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/services/index_refresh.py +0 -0
  181. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/services/marketplace.py +0 -0
  182. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/services/marketplace_api.py +0 -0
  183. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/services/marketplace_url.py +0 -0
  184. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/services/neutral_app.py +0 -0
  185. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/services/own_commands.py +0 -0
  186. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/services/preflight.py +0 -0
  187. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/services/pypi_quota.py +0 -0
  188. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/services/release_dry_run.py +0 -0
  189. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/services/security_scan.py +0 -0
  190. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/services/spl_store.py +0 -0
  191. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/services/web_container.py +0 -0
  192. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/feature/feature_.gitignore.j2 +0 -0
  193. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/feature/feature_MANIFEST.in.j2 +0 -0
  194. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/feature/feature_README.md.j2 +0 -0
  195. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/feature/feature_commands.py.j2 +0 -0
  196. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/feature/feature_config.py.j2 +0 -0
  197. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/feature/feature_docker-compose.dev.yml.j2 +0 -0
  198. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/feature/feature_docker-compose.prod.yml.j2 +0 -0
  199. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/feature/feature_docker.env.example.j2 +0 -0
  200. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/feature/feature_forms.py.j2 +0 -0
  201. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/feature/feature_frontend.npmrc.j2 +0 -0
  202. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/feature/feature_frontend_scripts.js.j2 +0 -0
  203. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/feature/feature_hooks.py.j2 +0 -0
  204. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/feature/feature_init.py.j2 +0 -0
  205. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/feature/feature_init_config.py.j2 +0 -0
  206. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/feature/feature_init_light.py.j2 +0 -0
  207. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/feature/feature_init_service.py.j2 +0 -0
  208. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/feature/feature_migrations_alembic.ini.j2 +0 -0
  209. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/feature/feature_migrations_env.py.j2 +0 -0
  210. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/feature/feature_migrations_script.py.mako.j2 +0 -0
  211. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/feature/feature_models.py.j2 +0 -0
  212. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/feature/feature_pyproject.toml.j2 +0 -0
  213. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/feature/feature_pyproject_minimal.toml.j2 +0 -0
  214. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/feature/feature_repositories.py.j2 +0 -0
  215. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/feature/feature_routes.py.j2 +0 -0
  216. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/feature/feature_scripts.js.j2 +0 -0
  217. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/feature/feature_seeders.py.j2 +0 -0
  218. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/feature/feature_services.py.j2 +0 -0
  219. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/feature/feature_services_service.py.j2 +0 -0
  220. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/feature/feature_signals.py.j2 +0 -0
  221. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/feature/feature_templates_index.html.j2 +0 -0
  222. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/feature/feature_tests_conftest.py.j2 +0 -0
  223. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/feature/feature_tests_e2e.py.j2 +0 -0
  224. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/feature/feature_tests_functional.py.j2 +0 -0
  225. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/feature/feature_tests_integration.py.j2 +0 -0
  226. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/feature/feature_tests_locustfile.py.j2 +0 -0
  227. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/feature/feature_tests_unit.py.j2 +0 -0
  228. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/feature/feature_webpack.config.js.j2 +0 -0
  229. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/licenses/COPYING +0 -0
  230. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/licenses/COPYING.LESSER +0 -0
  231. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/product/product_.env.dev.example.j2 +0 -0
  232. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/product/product_.env.prod.example.j2 +0 -0
  233. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/product/product_.gitignore.j2 +0 -0
  234. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/product/product_00_core_requirements_dev.sh.j2 +0 -0
  235. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/product/product_00_install_features.sh.j2 +0 -0
  236. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/product/product_01_compile_assets.sh.j2 +0 -0
  237. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/product/product_02_0_db_wait_connection.sh.j2 +0 -0
  238. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/product/product_02_1_db_create_db_test.sh.j2 +0 -0
  239. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/product/product_02_2_db_create_splent_migrations.sh.j2 +0 -0
  240. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/product/product_03_initialize_migrations.sh.j2 +0 -0
  241. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/product/product_04_handle_migrations.sh.j2 +0 -0
  242. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/product/product_05_0_start_app_dev.sh.j2 +0 -0
  243. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/product/product_05_1_start_app_prod.sh.j2 +0 -0
  244. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/product/product_400.html +0 -0
  245. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/product/product_401.html +0 -0
  246. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/product/product_404.html +0 -0
  247. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/product/product_500.html +0 -0
  248. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/product/product_Dockerfile.dev.dockerignore.j2 +0 -0
  249. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/product/product_Dockerfile.dev.j2 +0 -0
  250. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/product/product_Dockerfile.prod.dockerignore.j2 +0 -0
  251. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/product/product_Dockerfile.prod.j2 +0 -0
  252. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/product/product_README.md.j2 +0 -0
  253. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/product/product_app.css +0 -0
  254. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/product/product_app.js +0 -0
  255. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/product/product_base_template.html +0 -0
  256. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/product/product_ci_upgrade.yml.j2 +0 -0
  257. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/product/product_ci_validate.yml.j2 +0 -0
  258. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/product/product_config.py.j2 +0 -0
  259. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/product/product_docker-compose.dev.yml.j2 +0 -0
  260. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/product/product_docker-compose.prod.yml.j2 +0 -0
  261. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/product/product_dropzone.css +0 -0
  262. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/product/product_entrypoint.dev.sh.j2 +0 -0
  263. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/product/product_entrypoint.prod.sh.j2 +0 -0
  264. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/product/product_errors.py.j2 +0 -0
  265. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/product/product_favicon.svg +0 -0
  266. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/product/product_init.py.j2 +0 -0
  267. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/product/product_logging.py.j2 +0 -0
  268. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/product/product_own.css +0 -0
  269. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/product/product_package.json.j2 +0 -0
  270. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/product/product_pyproject.toml.j2 +0 -0
  271. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/templates/product/product_uvl.j2 +0 -0
  272. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/toolchain/Dockerfile.frontend +0 -0
  273. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/toolchain/frontend/package-lock.json +0 -0
  274. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/toolchain/frontend/package.json +0 -0
  275. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/toolchain/frontend/splent/build.js +0 -0
  276. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/toolchain/frontend/splent/legacy.js +0 -0
  277. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/toolchain/frontend/splent/lint.js +0 -0
  278. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/toolchain/frontend/splent/plugin.js +0 -0
  279. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/toolchain/frontend/splent/preset.js +0 -0
  280. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/toolchain/frontend/splent/singletons.json +0 -0
  281. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/utils/__init__.py +0 -0
  282. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/utils/archetype.py +0 -0
  283. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/utils/cache_utils.py +0 -0
  284. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/utils/ci_services.py +0 -0
  285. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/utils/ci_workflow.py +0 -0
  286. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/utils/command_loader.py +0 -0
  287. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/utils/contract_freshness.py +0 -0
  288. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/utils/db_client.py +0 -0
  289. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/utils/db_utils.py +0 -0
  290. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/utils/decorators.py +0 -0
  291. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/utils/deploy_freshness.py +0 -0
  292. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/utils/dynamic_imports.py +0 -0
  293. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/utils/feature_installer.py +0 -0
  294. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/utils/feature_naming.py +0 -0
  295. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/utils/feature_params.py +0 -0
  296. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/utils/feature_requirements.py +0 -0
  297. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/utils/feature_resolution.py +0 -0
  298. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/utils/feature_utils.py +0 -0
  299. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/utils/forge.py +0 -0
  300. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/utils/frontend_check.py +0 -0
  301. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/utils/frontend_licenses.py +0 -0
  302. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/utils/git_url.py +0 -0
  303. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/utils/integrity.py +0 -0
  304. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/utils/io_utils.py +0 -0
  305. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/utils/lifecycle.py +0 -0
  306. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/utils/manifest.py +0 -0
  307. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/utils/menu_keys.py +0 -0
  308. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/utils/migration_lock.py +0 -0
  309. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/utils/npm_semver.py +0 -0
  310. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/utils/path_utils.py +0 -0
  311. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/utils/proc.py +0 -0
  312. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/utils/redact.py +0 -0
  313. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/utils/refinement_facts.py +0 -0
  314. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/utils/running_version.py +0 -0
  315. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/utils/template_drift.py +0 -0
  316. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/utils/toml_edit.py +0 -0
  317. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/utils/upgrade_plan.py +0 -0
  318. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/utils/uvl_diagnosis.py +0 -0
  319. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli/utils/uvl_params.py +0 -0
  320. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli.egg-info/dependency_links.txt +0 -0
  321. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli.egg-info/entry_points.txt +0 -0
  322. {splent_cli-1.50.1 → splent_cli-1.52.0}/src/splent_cli.egg-info/requires.txt +0 -0
  323. {splent_cli-1.50.1 → splent_cli-1.52.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.50.1
3
+ Version: 1.52.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
  License-Expression: LGPL-3.0-or-later
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "splent_cli"
7
- version = "1.50.1"
7
+ version = "1.52.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"
@@ -6,6 +6,7 @@ import contextlib
6
6
  import json
7
7
  import os
8
8
  import subprocess
9
+ import sys
9
10
  import tempfile
10
11
 
11
12
  import click
@@ -28,6 +29,8 @@ from splent_cli.services import (
28
29
  image_registry,
29
30
  release,
30
31
  release_gate,
32
+ release_workspace,
33
+ source_mirror,
31
34
  )
32
35
  from splent_cli.utils.proc import run, require_docker
33
36
 
@@ -39,19 +42,9 @@ def _guard_all_features_pinned(product_path: str):
39
42
  features_prod declare, so an editable entry in any of them makes the
40
43
  release irreproducible, not only one in the base list.
41
44
  """
42
- from splent_cli.utils.feature_utils import (
43
- FEATURE_LIST_KEYS,
44
- load_product_pyproject,
45
- read_feature_list,
46
- )
45
+ from splent_cli.utils.feature_utils import load_product_pyproject
47
46
 
48
- data = load_product_pyproject(product_path)
49
- editable = [
50
- (key, entry)
51
- for key in FEATURE_LIST_KEYS
52
- for entry in read_feature_list(data, key)
53
- if "@" not in entry
54
- ]
47
+ editable = release_workspace.editable_features(load_product_pyproject(product_path))
55
48
  if not editable:
56
49
  return
57
50
 
@@ -385,6 +378,12 @@ def _left_out_flags(channels) -> list[str]:
385
378
  is_flag=True,
386
379
  help="Do not build or push the Docker image for this version.",
387
380
  )
381
+ @click.option(
382
+ "--no-mirror",
383
+ is_flag=True,
384
+ help="Do not publish to [tool.splent.release.source_mirror] now, for when it "
385
+ "is down. splent release:resume does it later.",
386
+ )
388
387
  @click.option(
389
388
  "--allow-unfinished",
390
389
  is_flag=True,
@@ -403,6 +402,7 @@ def product_release(
403
402
  no_forge,
404
403
  no_github,
405
404
  no_docker,
405
+ no_mirror,
406
406
  allow_unfinished,
407
407
  wait,
408
408
  ):
@@ -419,8 +419,16 @@ def product_release(
419
419
  click.secho(f" error: pyproject.toml not found in {product}", fg="red")
420
420
  raise SystemExit(1)
421
421
 
422
+ if release_workspace.in_development_mode(product_path):
423
+ raise SystemExit(
424
+ release_workspace.run_from_head(
425
+ product, product_path, str(context.workspace()), sys.argv[1:]
426
+ )
427
+ )
428
+
422
429
  _guard_all_features_pinned(product_path)
423
430
  _guard_deployable(str(context.workspace()), product, product_path)
431
+ mirror = None if no_mirror else _declared_source_mirror(product_path)
424
432
 
425
433
  # Determine org/repo for the semver wizard
426
434
  repo = release.get_repo_from_path(product_path)
@@ -502,7 +510,16 @@ def product_release(
502
510
  ),
503
511
  post_pypi_hook=_docker_hook,
504
512
  wait=wait,
513
+ source_mirror=mirror,
505
514
  )
506
515
 
507
516
 
517
+ def _declared_source_mirror(product_path: str):
518
+ try:
519
+ return source_mirror.declared(os.path.join(product_path, "pyproject.toml"))
520
+ except source_mirror.MirrorDeclarationError as e:
521
+ click.secho(f" error: {e}", fg="red")
522
+ raise SystemExit(1)
523
+
524
+
508
525
  cli_command = product_release
@@ -33,11 +33,18 @@ import contextlib
33
33
  import os
34
34
  import shutil
35
35
  import subprocess
36
+ import sys
36
37
  import tempfile
37
38
 
38
39
  import click
39
40
 
40
- from splent_cli.services import context, release, release_gate
41
+ from splent_cli.services import (
42
+ context,
43
+ release,
44
+ release_gate,
45
+ release_workspace,
46
+ source_mirror,
47
+ )
41
48
  from splent_cli.utils import forge
42
49
  from splent_cli.utils.git_url import _non_interactive_env
43
50
 
@@ -322,6 +329,13 @@ def release_resume(target, assume_yes, no_pypi, no_forge, no_github, no_docker,
322
329
  no_forge = release.no_forge_requested(no_forge, no_github)
323
330
  workspace = str(context.workspace())
324
331
  path, label, kind = resolve_target(target, workspace)
332
+ if kind == "product" and release_workspace.in_development_mode(path):
333
+ raise SystemExit(
334
+ release_workspace.run_from_head(
335
+ os.path.basename(path), path, workspace, sys.argv[1:]
336
+ )
337
+ )
338
+
325
339
  # What the hints this run prints tell the operator to run next. A withheld
326
340
  # image stays withheld.
327
341
  hint_target = f"{target} --no-docker" if no_docker else target
@@ -539,6 +553,27 @@ def release_resume(target, assume_yes, no_pypi, no_forge, no_github, no_docker,
539
553
  if make_snapshot:
540
554
  steps.append(f"create the local snapshot for {tag}")
541
555
 
556
+ # The product's official repository, once the forge has what it copies.
557
+ mirror = None
558
+ if kind == "product" and release_gate.FORGE in channels:
559
+ try:
560
+ mirror = source_mirror.declared(pyproject)
561
+ if mirror:
562
+ mirror_steps = source_mirror.missing(mirror, path, tag)
563
+ steps.extend(mirror_steps)
564
+ mirror = mirror if mirror_steps else None
565
+ except source_mirror.MirrorDeclarationError as e:
566
+ click.secho(f" error: {e}", fg="red")
567
+ raise SystemExit(1)
568
+ except source_mirror.MirrorUnreachable as e:
569
+ stuck.append(
570
+ release_gate.ChannelStatus(
571
+ source_mirror.CHANNEL,
572
+ summary=f"could not ask {mirror.web_url} what it has ({e})",
573
+ )
574
+ )
575
+ mirror = None
576
+
542
577
  click.echo()
543
578
  if not steps:
544
579
  if stuck:
@@ -675,6 +710,11 @@ def release_resume(target, assume_yes, no_pypi, no_forge, no_github, no_docker,
675
710
  if failure:
676
711
  failures.append(f"the release for {tag} on the forge ({failure})")
677
712
 
713
+ if mirror:
714
+ failure = source_mirror.publish(mirror, path, tag)
715
+ if failure:
716
+ failures.append(f"{tag} on {mirror.web_url} ({failure})")
717
+
678
718
  if push_image:
679
719
  from splent_cli.commands.product.product_release import release_docker_image
680
720
 
@@ -740,6 +740,10 @@ def verify_assets(assets, *, lock=None, production: bool = False) -> list[str]:
740
740
  if dist.is_dir():
741
741
  for path in sorted(dist.rglob("*")):
742
742
  name = path.relative_to(dist).as_posix()
743
+ # pip compiles the .py a bundle ships to the browser (a pyodide
744
+ # wrapper) where it installs it: that bytecode is no file of it.
745
+ if "__pycache__" in path.parts:
746
+ continue
743
747
  if path.is_file() and name not in listed:
744
748
  problems.append(f"assets/dist/{name} is not in the manifest")
745
749
  if lock is not None and Path(lock).is_file():
@@ -402,27 +402,33 @@ def github_create_release(
402
402
  draft: bool = False,
403
403
  prerelease: bool = False,
404
404
  timeout: int = 30,
405
+ api_base: str | None = None,
406
+ generate_notes: bool = False,
405
407
  ) -> ReleaseResult:
406
- """Create a release for *tag* on the configured forge.
408
+ """Create a release for *tag* on the configured forge, or at *api_base*.
407
409
 
408
410
  Returns the outcome instead of raising for HTTP failures, so the caller can
409
411
  tell "already there" (idempotent rerun) from "refused" (a divergence, since
410
412
  the tag exists by the time this runs). Raises :class:`RegistryError` only
411
413
  when the forge cannot be reached at all.
414
+
415
+ ``generate_notes`` asks GitHub to append what changed since the last release
416
+ to *body*. Only GitHub knows it.
412
417
  """
413
- payload = json.dumps(
414
- {
415
- "tag_name": tag,
416
- "name": name,
417
- "body": body,
418
- "draft": draft,
419
- "prerelease": prerelease,
420
- }
421
- ).encode()
418
+ fields = {
419
+ "tag_name": tag,
420
+ "name": name,
421
+ "body": body,
422
+ "draft": draft,
423
+ "prerelease": prerelease,
424
+ }
425
+ if generate_notes:
426
+ fields["generate_release_notes"] = True
427
+ payload = json.dumps(fields).encode()
422
428
  headers = _github_headers(token)
423
429
  headers["Content-Type"] = "application/json"
424
430
  req = _forge_request(
425
- f"{forge.api_base()}/repos/{org}/{repo}/releases",
431
+ f"{api_base or forge.api_base()}/repos/{org}/{repo}/releases",
426
432
  data=payload,
427
433
  headers=headers,
428
434
  method="POST",
@@ -16,6 +16,7 @@ import tomllib
16
16
  import click
17
17
 
18
18
  from splent_cli.services import release_gate
19
+ from splent_cli.services import source_mirror as source_mirror_service
19
20
  from splent_cli.utils import forge
20
21
  from splent_cli.utils.git_url import _non_interactive_env
21
22
  from splent_cli.utils.io_utils import atomic_write
@@ -1619,6 +1620,7 @@ def run_release_pipeline(
1619
1620
  post_pypi_hook=None,
1620
1621
  wait: bool = False,
1621
1622
  neutral: bool = False,
1623
+ source_mirror=None,
1622
1624
  ):
1623
1625
  """Run the standard release pipeline.
1624
1626
 
@@ -1634,7 +1636,8 @@ def run_release_pipeline(
1634
1636
  7. Commit (local, revertible)
1635
1637
  8. Build and upload to PyPI
1636
1638
  9. Push the branch, the tag, and create the release on the git host
1637
- 10. (optional) post_pypi_hook, e.g. the snapshot or the Docker image
1639
+ 10. (optional) the same on source_mirror, the product's official repository
1640
+ 11. (optional) post_pypi_hook, e.g. the snapshot or the Docker image
1638
1641
 
1639
1642
  The order of 8 and 9 is the point. A PyPI version can never be replaced or
1640
1643
  removed; a tag that was never pushed costs nothing. Uploading first means a
@@ -1714,6 +1717,10 @@ def run_release_pipeline(
1714
1717
  deep=deep,
1715
1718
  allow_unfinished=allow_unfinished,
1716
1719
  )
1720
+ if source_mirror and to_forge:
1721
+ report.statuses.append(
1722
+ source_mirror_service.check(source_mirror, path, tag)
1723
+ )
1717
1724
  release_gate.render(report, header=header)
1718
1725
  if not report.ok:
1719
1726
  release_gate.refuse(report, resume_target=target)
@@ -1852,6 +1859,14 @@ def run_release_pipeline(
1852
1859
  )
1853
1860
  if failure:
1854
1861
  failures.append(f"the release for {tag} on the git host ({failure})")
1862
+ # Before the image: the version the image reaches production with
1863
+ # must already have its page where the app links to it.
1864
+ if source_mirror:
1865
+ failure = source_mirror_service.publish(source_mirror, path, tag)
1866
+ if failure:
1867
+ failures.append(f"{tag} on {source_mirror.web_url} ({failure})")
1868
+ else:
1869
+ accepted.append(source_mirror.web_url)
1855
1870
  else:
1856
1871
  create_and_push_tag(path, tag, push=False)
1857
1872
  click.secho(
@@ -195,7 +195,7 @@ def canonical_channel(name) -> str:
195
195
  return CHANNEL_ALIASES.get(key, key)
196
196
 
197
197
 
198
- _RELEASE_KEYS = {"channels", "registries", "mirrors"}
198
+ _RELEASE_KEYS = {"channels", "registries", "mirrors", "source_mirror"}
199
199
 
200
200
 
201
201
  def declared_channels(pyproject_path: str) -> tuple[str, ...]:
@@ -234,7 +234,7 @@ def declared_channels(pyproject_path: str) -> tuple[str, ...]:
234
234
  raise ChannelDeclarationError(
235
235
  "[tool.splent.release] has unknown key(s) "
236
236
  + ", ".join(unknown)
237
- + ". The keys are 'channels', 'registries' and 'mirrors', so this was "
237
+ + ". The keys are 'channels', 'registries', 'mirrors' and 'source_mirror', so this was "
238
238
  "ignored silently before."
239
239
  )
240
240
 
@@ -0,0 +1,180 @@
1
+ """Releasing what HEAD holds while the checkout is in development mode.
2
+
3
+ A product under development lists its features without a version in
4
+ pyproject.toml, uncommitted, so the app mounts their working copies. HEAD keeps
5
+ them pinned. Such a checkout cannot release as it is, and it should not have to
6
+ change either: a release is what is committed.
7
+
8
+ So product:release and release:resume run from a temporary workspace of their
9
+ own, a worktree of HEAD next to the cache and the product line's model, and the
10
+ checkout moves forward afterwards with its pyproject.toml as it was, bar what
11
+ the release changed in it.
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ import glob
17
+ import os
18
+ import shutil
19
+ import subprocess
20
+ import sys
21
+ import tempfile
22
+ import tomllib
23
+
24
+ import click
25
+
26
+ from splent_cli.utils.feature_utils import (
27
+ FEATURE_LIST_KEYS,
28
+ load_product_pyproject,
29
+ read_feature_list,
30
+ )
31
+
32
+ PYPROJECT = "pyproject.toml"
33
+
34
+
35
+ def editable_features(data: dict) -> list[tuple[str, str]]:
36
+ """``(list, entry)`` of every feature of a pyproject with no version pinned.
37
+
38
+ Every list counts. A release runs whatever features, features_dev and
39
+ features_prod declare.
40
+ """
41
+ return [
42
+ (key, entry)
43
+ for key in FEATURE_LIST_KEYS
44
+ for entry in read_feature_list(data, key)
45
+ if "@" not in entry
46
+ ]
47
+
48
+
49
+ def _git(path: str, *args: str) -> subprocess.CompletedProcess:
50
+ return subprocess.run(["git", *args], cwd=path, capture_output=True, text=True)
51
+
52
+
53
+ def in_development_mode(product_path: str) -> bool:
54
+ """Whether the checkout has editable features and HEAD has none."""
55
+ if not editable_features(load_product_pyproject(product_path)):
56
+ return False
57
+ head = _git(product_path, "show", f"HEAD:{PYPROJECT}")
58
+ if head.returncode != 0:
59
+ return False
60
+ try:
61
+ return not editable_features(tomllib.loads(head.stdout))
62
+ except tomllib.TOMLDecodeError:
63
+ return False
64
+
65
+
66
+ def _splent(args: list[str], env: dict) -> int:
67
+ """Run the CLI in the temporary workspace, in this terminal."""
68
+ return subprocess.run(
69
+ [sys.executable, "-m", "splent_cli", *args], env=env
70
+ ).returncode
71
+
72
+
73
+ def _merged_pyproject(path: str, ours: str, base: str, theirs: str) -> str | None:
74
+ """Three-way merge of the checkout's pyproject.toml, None on a conflict."""
75
+ with tempfile.TemporaryDirectory(prefix="splent_pyproject_") as tmp:
76
+ names = []
77
+ for name, content in (("ours", ours), ("base", base), ("theirs", theirs)):
78
+ names.append(os.path.join(tmp, name))
79
+ with open(names[-1], "w", encoding="utf-8") as f:
80
+ f.write(content)
81
+ merged = _git(path, "merge-file", "-p", *names)
82
+ return merged.stdout if merged.returncode == 0 else None
83
+
84
+
85
+ def _bring_checkout_forward(product_path: str, start: str, end: str) -> None:
86
+ """Move the checkout to *end*, its development pyproject.toml kept.
87
+
88
+ Says so when it cannot, and leaves the checkout exactly as it found it.
89
+ """
90
+ hint = f"Your checkout stays where it was. When it can, run git merge --ff-only {end[:12]}."
91
+ if _git(product_path, "rev-parse", "HEAD").stdout.strip() != start:
92
+ click.secho(f" checkout HEAD moved during the release. {hint}", fg="yellow")
93
+ return
94
+ pyproject = os.path.join(product_path, PYPROJECT)
95
+ with open(pyproject, encoding="utf-8") as f:
96
+ ours = f.read()
97
+ merged = _merged_pyproject(
98
+ product_path,
99
+ ours,
100
+ _git(product_path, "show", f"{start}:{PYPROJECT}").stdout,
101
+ _git(product_path, "show", f"{end}:{PYPROJECT}").stdout,
102
+ )
103
+ if merged is None:
104
+ click.secho(
105
+ f" checkout your {PYPROJECT} and the release's do not merge. {hint}",
106
+ fg="yellow",
107
+ )
108
+ return
109
+
110
+ result = merged
111
+ moved = False
112
+ try:
113
+ _git(product_path, "checkout", "--", PYPROJECT)
114
+ forward = _git(product_path, "merge", "--ff-only", "--quiet", end)
115
+ moved = forward.returncode == 0
116
+ if not moved:
117
+ result = ours
118
+ click.secho(
119
+ f" checkout {forward.stderr.strip()}\n checkout {hint}", fg="yellow"
120
+ )
121
+ except OSError as e:
122
+ result = ours
123
+ click.secho(f" checkout {e}. {hint}", fg="yellow")
124
+ finally:
125
+ with open(pyproject, "w", encoding="utf-8") as f:
126
+ f.write(result)
127
+ if moved:
128
+ click.echo(f" checkout now at {end[:12]}, your {PYPROJECT} is kept")
129
+
130
+
131
+ def run_from_head(
132
+ product: str, product_path: str, workspace: str, argv: list[str]
133
+ ) -> int:
134
+ """Run this command in a temporary workspace holding HEAD. Its exit code.
135
+
136
+ The checkout ends where a release run in it would have, commit included
137
+ when the command stopped halfway, so release:resume can go on from it.
138
+ """
139
+ start = _git(product_path, "rev-parse", "HEAD").stdout.strip()
140
+ click.secho(
141
+ f" checkout {product} has editable features, so this works from what HEAD "
142
+ f"holds ({start[:12]}).",
143
+ fg="cyan",
144
+ )
145
+ status = _git(product_path, "status", "--porcelain").stdout.splitlines()
146
+ left_out = [line[3:] for line in status if line[3:] != PYPROJECT]
147
+ if left_out:
148
+ click.secho(
149
+ " checkout uncommitted, so left out: "
150
+ + ", ".join(left_out[:5])
151
+ + (" ..." if len(left_out) > 5 else ""),
152
+ fg="yellow",
153
+ )
154
+
155
+ temporary = tempfile.mkdtemp(prefix="splent_release_")
156
+ worktree = os.path.join(temporary, product)
157
+ try:
158
+ cache = os.path.join(workspace, ".splent_cache")
159
+ for path in [cache, *glob.glob(os.path.join(workspace, "splent_spl_*"))]:
160
+ if os.path.exists(path):
161
+ os.symlink(path, os.path.join(temporary, os.path.basename(path)))
162
+ added = _git(product_path, "worktree", "add", "--detach", worktree, start)
163
+ if added.returncode != 0:
164
+ click.secho(f" error: {added.stderr.strip()}", fg="red")
165
+ return 1
166
+
167
+ env = {**os.environ, "WORKING_DIR": temporary, "SPLENT_APP": product}
168
+ code = _splent(["product:resolve", "--prod", "--strict"], env)
169
+ if code != 0:
170
+ return code
171
+ code = _splent(argv, env)
172
+
173
+ end = _git(worktree, "rev-parse", "HEAD").stdout.strip()
174
+ if end and end != start:
175
+ _bring_checkout_forward(product_path, start, end)
176
+ return code
177
+ finally:
178
+ _git(product_path, "worktree", "remove", "--force", worktree)
179
+ _git(product_path, "worktree", "prune")
180
+ shutil.rmtree(temporary, ignore_errors=True)