splent-cli 1.22.2__tar.gz → 1.23.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 (195) hide show
  1. {splent_cli-1.22.2/src/splent_cli.egg-info → splent_cli-1.23.0}/PKG-INFO +1 -1
  2. {splent_cli-1.22.2 → splent_cli-1.23.0}/pyproject.toml +1 -1
  3. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/check/check_contracts.py +24 -6
  4. splent_cli-1.23.0/src/splent_cli/commands/check/check_github.py +126 -0
  5. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/feature/feature_fork.py +30 -14
  6. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/feature/feature_release.py +9 -2
  7. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/feature/feature_unlock.py +9 -3
  8. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/product/product_build.py +19 -0
  9. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/tokens_setup.py +31 -11
  10. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/services/index_refresh.py +54 -24
  11. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/services/preflight.py +28 -15
  12. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/services/registry.py +102 -48
  13. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/services/release.py +66 -51
  14. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/services/release_gate.py +20 -10
  15. splent_cli-1.23.0/src/splent_cli/utils/forge.py +224 -0
  16. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/utils/git_url.py +47 -28
  17. {splent_cli-1.22.2 → splent_cli-1.23.0/src/splent_cli.egg-info}/PKG-INFO +1 -1
  18. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli.egg-info/SOURCES.txt +1 -0
  19. splent_cli-1.22.2/src/splent_cli/commands/check/check_github.py +0 -105
  20. {splent_cli-1.22.2 → splent_cli-1.23.0}/LICENSE +0 -0
  21. {splent_cli-1.22.2 → splent_cli-1.23.0}/README.md +0 -0
  22. {splent_cli-1.22.2 → splent_cli-1.23.0}/setup.cfg +0 -0
  23. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/__init__.py +0 -0
  24. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/__main__.py +0 -0
  25. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/cli.py +0 -0
  26. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/__init__.py +0 -0
  27. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/cache/__init__.py +0 -0
  28. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/cache/cache_clear.py +0 -0
  29. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/cache/cache_orphans.py +0 -0
  30. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/cache/cache_outdated.py +0 -0
  31. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/cache/cache_prune.py +0 -0
  32. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/cache/cache_size.py +0 -0
  33. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/cache/cache_status.py +0 -0
  34. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/cache/cache_usage.py +0 -0
  35. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/cache/cache_versions.py +0 -0
  36. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/check/__init__.py +0 -0
  37. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/check/check_deps.py +0 -0
  38. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/check/check_docker.py +0 -0
  39. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/check/check_env.py +0 -0
  40. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/check/check_features.py +0 -0
  41. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/check/check_infra.py +0 -0
  42. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/check/check_product.py +0 -0
  43. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/check/check_pypi.py +0 -0
  44. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/check/check_pyproject.py +0 -0
  45. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/check/check_releases.py +0 -0
  46. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/clear/__init__.py +0 -0
  47. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/clear/clear_build.py +0 -0
  48. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/clear/clear_log.py +0 -0
  49. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/clear/clear_uploads.py +0 -0
  50. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/command/__init__.py +0 -0
  51. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/command/command_create.py +0 -0
  52. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/coverage.py +0 -0
  53. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/database/db_console.py +0 -0
  54. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/database/db_dump.py +0 -0
  55. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/database/db_migrate.py +0 -0
  56. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/database/db_reset.py +0 -0
  57. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/database/db_restore.py +0 -0
  58. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/database/db_rollback.py +0 -0
  59. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/database/db_seed.py +0 -0
  60. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/database/db_status.py +0 -0
  61. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/database/db_upgrade.py +0 -0
  62. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/doctor.py +0 -0
  63. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/env/env_list.py +0 -0
  64. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/env/env_set.py +0 -0
  65. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/env/env_show.py +0 -0
  66. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/export/__init__.py +0 -0
  67. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/export/export_puml.py +0 -0
  68. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/feature/feature_add.py +0 -0
  69. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/feature/feature_attach.py +0 -0
  70. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/feature/feature_clean.py +0 -0
  71. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/feature/feature_clone.py +0 -0
  72. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/feature/feature_compat.py +0 -0
  73. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/feature/feature_compile.py +0 -0
  74. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/feature/feature_contract.py +0 -0
  75. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/feature/feature_create.py +0 -0
  76. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/feature/feature_delete.py +0 -0
  77. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/feature/feature_detach.py +0 -0
  78. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/feature/feature_discard.py +0 -0
  79. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/feature/feature_drift.py +0 -0
  80. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/feature/feature_env.py +0 -0
  81. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/feature/feature_git.py +0 -0
  82. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/feature/feature_hook_add.py +0 -0
  83. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/feature/feature_hook_remove.py +0 -0
  84. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/feature/feature_hooks.py +0 -0
  85. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/feature/feature_impact.py +0 -0
  86. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/feature/feature_info.py +0 -0
  87. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/feature/feature_inject_config.py +0 -0
  88. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/feature/feature_install.py +0 -0
  89. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/feature/feature_list.py +0 -0
  90. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/feature/feature_order.py +0 -0
  91. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/feature/feature_outdated.py +0 -0
  92. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/feature/feature_pin.py +0 -0
  93. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/feature/feature_pip_install.py +0 -0
  94. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/feature/feature_pull.py +0 -0
  95. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/feature/feature_refine.py +0 -0
  96. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/feature/feature_remove.py +0 -0
  97. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/feature/feature_rename.py +0 -0
  98. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/feature/feature_search.py +0 -0
  99. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/feature/feature_status.py +0 -0
  100. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/feature/feature_sync_template.py +0 -0
  101. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/feature/feature_test.py +0 -0
  102. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/feature/feature_translate.py +0 -0
  103. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/feature/feature_upgrade.py +0 -0
  104. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/feature/feature_versions.py +0 -0
  105. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/feature/feature_xray.py +0 -0
  106. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/lint.py +0 -0
  107. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/locust.py +0 -0
  108. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/marketplace/login.py +0 -0
  109. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/marketplace/logout.py +0 -0
  110. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/marketplace/marketplace_auth_utils.py +0 -0
  111. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/marketplace/marketplace_index.py +0 -0
  112. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/marketplace/whoami.py +0 -0
  113. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/product/__init__.py +0 -0
  114. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/product/product_auto_require.py +0 -0
  115. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/product/product_clean.py +0 -0
  116. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/product/product_commands.py +0 -0
  117. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/product/product_config.py +0 -0
  118. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/product/product_configure.py +0 -0
  119. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/product/product_console.py +0 -0
  120. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/product/product_containers.py +0 -0
  121. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/product/product_create.py +0 -0
  122. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/product/product_deploy.py +0 -0
  123. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/product/product_derive.py +0 -0
  124. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/product/product_deselect.py +0 -0
  125. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/product/product_down.py +0 -0
  126. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/product/product_drift.py +0 -0
  127. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/product/product_env.py +0 -0
  128. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/product/product_list.py +0 -0
  129. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/product/product_logs.py +0 -0
  130. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/product/product_missing.py +0 -0
  131. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/product/product_port.py +0 -0
  132. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/product/product_release.py +0 -0
  133. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/product/product_resolve.py +0 -0
  134. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/product/product_restart.py +0 -0
  135. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/product/product_routes.py +0 -0
  136. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/product/product_run.py +0 -0
  137. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/product/product_select.py +0 -0
  138. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/product/product_shell.py +0 -0
  139. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/product/product_signals.py +0 -0
  140. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/product/product_sync_template.py +0 -0
  141. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/product/product_test.py +0 -0
  142. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/product/product_up.py +0 -0
  143. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/product/product_validate.py +0 -0
  144. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/release/__init__.py +0 -0
  145. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/release/release_core.py +0 -0
  146. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/release/release_resume.py +0 -0
  147. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/selenium.py +0 -0
  148. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/spl/__init__.py +0 -0
  149. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/spl/spl_add_constraints.py +0 -0
  150. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/spl/spl_add_feature.py +0 -0
  151. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/spl/spl_compare.py +0 -0
  152. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/spl/spl_configurations.py +0 -0
  153. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/spl/spl_create.py +0 -0
  154. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/spl/spl_deps.py +0 -0
  155. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/spl/spl_features.py +0 -0
  156. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/spl/spl_fetch.py +0 -0
  157. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/spl/spl_info.py +0 -0
  158. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/spl/spl_list.py +0 -0
  159. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/spl/spl_migrate_catalog.py +0 -0
  160. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/spl/spl_outdated.py +0 -0
  161. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/spl/spl_pin.py +0 -0
  162. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/spl/spl_publish.py +0 -0
  163. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/spl/spl_remove_feature.py +0 -0
  164. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/spl/spl_utils.py +0 -0
  165. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/uvl/uvl_utils.py +0 -0
  166. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/commands/version.py +0 -0
  167. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/services/__init__.py +0 -0
  168. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/services/compose.py +0 -0
  169. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/services/context.py +0 -0
  170. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/services/credentials.py +0 -0
  171. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/services/marketplace.py +0 -0
  172. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/services/marketplace_api.py +0 -0
  173. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/services/marketplace_url.py +0 -0
  174. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/services/spl_store.py +0 -0
  175. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/utils/__init__.py +0 -0
  176. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/utils/archetype.py +0 -0
  177. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/utils/cache_utils.py +0 -0
  178. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/utils/command_loader.py +0 -0
  179. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/utils/contract_freshness.py +0 -0
  180. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/utils/db_utils.py +0 -0
  181. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/utils/decorators.py +0 -0
  182. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/utils/dynamic_imports.py +0 -0
  183. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/utils/feature_installer.py +0 -0
  184. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/utils/feature_utils.py +0 -0
  185. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/utils/integrity.py +0 -0
  186. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/utils/io_utils.py +0 -0
  187. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/utils/lifecycle.py +0 -0
  188. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/utils/manifest.py +0 -0
  189. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/utils/path_utils.py +0 -0
  190. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/utils/proc.py +0 -0
  191. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli/utils/template_drift.py +0 -0
  192. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli.egg-info/dependency_links.txt +0 -0
  193. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli.egg-info/entry_points.txt +0 -0
  194. {splent_cli-1.22.2 → splent_cli-1.23.0}/src/splent_cli.egg-info/requires.txt +0 -0
  195. {splent_cli-1.22.2 → splent_cli-1.23.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.22.2
3
+ Version: 1.23.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.22.2"
7
+ version = "1.23.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"
@@ -17,6 +17,7 @@ import click
17
17
  import tomllib
18
18
 
19
19
  from splent_cli.services import context, marketplace, spl_store
20
+ from splent_cli.utils import forge
20
21
 
21
22
 
22
23
  def _snapshot_version_key(pyproject_path: Path) -> tuple:
@@ -65,7 +66,7 @@ def _local_contract_requires(workspace: str, package: str) -> list[str] | None:
65
66
 
66
67
 
67
68
  def _exists_remotely(org: str | None, package: str) -> bool:
68
- """Whether a feature not present locally at least exists on GitHub.
69
+ """Whether a feature not present locally at least exists on the forge.
69
70
 
70
71
  Answers True whenever the question cannot be settled: no org to look
71
72
  under, no network, a rate limit, anything unexpected. A diagnostic that
@@ -78,10 +79,27 @@ def _exists_remotely(org: str | None, package: str) -> bool:
78
79
  import urllib.error
79
80
  import urllib.request
80
81
 
81
- # The UVL writes the org the way GitHub spells it ("splent-io"), which is
82
- # not the way the filesystem does ("splent_io"), so it is used verbatim.
83
- url = f"https://github.com/{org}/{package}"
84
- request = urllib.request.Request(url, method="HEAD")
82
+ # The UVL writes the org the way the forge spells it ("splent-io"), which
83
+ # is not the way the filesystem does ("splent_io"), so it is used verbatim.
84
+ #
85
+ # GitHub keeps the anonymous HEAD against the web URL it has always used.
86
+ # A self-hosted forge is far likelier to keep its repositories private, and
87
+ # a private repository answers 404 to a stranger, which would read here as
88
+ # a feature nobody ever wrote. When such a forge gives us a token we ask
89
+ # its API instead, with GET because Gitea-compatible routes are registered
90
+ # for GET alone and answer a HEAD with 405.
91
+ token = None if forge.is_github() else forge.token()
92
+ if token:
93
+ request = urllib.request.Request(
94
+ f"{forge.api_base()}/repos/{org}/{package}",
95
+ headers={
96
+ "Authorization": f"token {token}",
97
+ "Accept": "application/json",
98
+ "User-Agent": "splent-cli",
99
+ },
100
+ )
101
+ else:
102
+ request = urllib.request.Request(forge.web_url(org, package), method="HEAD")
85
103
  try:
86
104
  with urllib.request.urlopen(request, timeout=10) as response:
87
105
  return response.status < 400
@@ -230,7 +248,7 @@ def check_contracts(spl_name):
230
248
  click.secho(
231
249
  f" ✗ {short} is offered by the model but does not exist: "
232
250
  f"{meta.get('org')}/{meta['package']} is not in this workspace, "
233
- f"not in the cache and not on GitHub",
251
+ f"not in the cache and not on {forge.host()}",
234
252
  fg="red",
235
253
  )
236
254
  click.echo(
@@ -0,0 +1,126 @@
1
+ import os
2
+ import urllib.request
3
+ import urllib.error
4
+ import json
5
+ import click
6
+
7
+ from splent_cli.utils import forge
8
+
9
+
10
+ @click.command(
11
+ "check:github",
12
+ short_help="Verify forge credentials from .env (GITHUB_USER / forge token)",
13
+ )
14
+ def check_github():
15
+ # The command keeps its name, but the forge it checks is whatever the
16
+ # workspace is configured against: github.com by default, a self-hosted
17
+ # Forgejo when SPLENT_FORGE_HOST says so.
18
+ forge_host = forge.host()
19
+ token_var = forge.token_env_name()
20
+
21
+ click.echo(click.style(f"\n{forge_host} Credentials Check\n", fg="cyan", bold=True))
22
+
23
+ user = os.getenv("GITHUB_USER", "").strip()
24
+ # Resolved through forge so a self-hosted forge reads SPLENT_FORGE_TOKEN
25
+ # while GitHub keeps reading GITHUB_TOKEN, as it always has.
26
+ token = (forge.token() or "").strip()
27
+
28
+ # --- presence checks ---
29
+ if not user:
30
+ click.echo(click.style("[✖] ", fg="red") + "GITHUB_USER not set in .env")
31
+ click.secho(
32
+ " Run 'splent tokens:setup' for setup instructions.", fg="bright_black"
33
+ )
34
+ raise SystemExit(1)
35
+ click.echo(click.style("[✔] ", fg="green") + f"GITHUB_USER = {user}")
36
+
37
+ if not token:
38
+ click.echo(click.style("[✖] ", fg="red") + f"{token_var} not set in .env")
39
+ click.secho(
40
+ " Run 'splent tokens:setup' for setup instructions.", fg="bright_black"
41
+ )
42
+ raise SystemExit(1)
43
+
44
+ masked = token[:4] + "*" * (len(token) - 8) + token[-4:]
45
+ click.echo(click.style("[✔] ", fg="green") + f"{token_var} = {masked}")
46
+
47
+ # --- API call ---
48
+ # Vendor media types are GitHub's own; a Gitea-compatible forge does not
49
+ # know them and answers plain JSON, so they are only sent to GitHub.
50
+ headers = {
51
+ "Authorization": f"token {token}",
52
+ "Accept": "application/json",
53
+ "User-Agent": "splent-cli",
54
+ }
55
+ if forge.is_github():
56
+ headers["Accept"] = "application/vnd.github+json"
57
+ headers["X-GitHub-Api-Version"] = "2022-11-28"
58
+
59
+ click.echo(f"\nContacting the {forge_host} API...")
60
+ req = urllib.request.Request(f"{forge.api_base()}/user", headers=headers)
61
+
62
+ try:
63
+ with urllib.request.urlopen(req, timeout=10) as resp:
64
+ data = json.loads(resp.read().decode())
65
+ rate_remaining = resp.headers.get("X-RateLimit-Remaining", "?")
66
+ rate_limit = resp.headers.get("X-RateLimit-Limit", "?")
67
+ except urllib.error.HTTPError as e:
68
+ if e.code == 401:
69
+ click.echo(
70
+ click.style("[✖] ", fg="red")
71
+ + "Token invalid or expired (401 Unauthorized)"
72
+ )
73
+ click.secho(
74
+ " Run 'splent tokens:setup' for instructions on obtaining a valid token.",
75
+ fg="bright_black",
76
+ )
77
+ elif e.code == 403:
78
+ click.echo(
79
+ click.style("[✖] ", fg="red")
80
+ + "Token lacks required permissions (403 Forbidden)"
81
+ )
82
+ scope = "repo" if forge.is_github() else "write:repository"
83
+ click.secho(
84
+ f" Run 'splent tokens:setup', the token needs the '{scope}' scope.",
85
+ fg="bright_black",
86
+ )
87
+ else:
88
+ click.echo(
89
+ click.style("[✖] ", fg="red") + f"{forge_host} API error: HTTP {e.code}"
90
+ )
91
+ raise SystemExit(1)
92
+ except urllib.error.URLError as e:
93
+ click.echo(click.style("[✖] ", fg="red") + f"Network error: {e.reason}")
94
+ raise SystemExit(1)
95
+
96
+ # --- validate identity ---
97
+ api_login = data.get("login", "")
98
+ if api_login.lower() != user.lower():
99
+ click.echo(
100
+ click.style("[⚠] ", fg="yellow")
101
+ + f"Token belongs to '{api_login}', but GITHUB_USER is '{user}'"
102
+ )
103
+ else:
104
+ click.echo(click.style("[✔] ", fg="green") + f"Authenticated as {api_login}")
105
+
106
+ # GitHub calls the display name "name"; a Gitea-compatible forge calls it
107
+ # "full_name", so without the fallback every Forgejo check reported "-".
108
+ name = data.get("name") or data.get("full_name") or "-"
109
+ click.echo(click.style("[✔] ", fg="green") + f"Name: {name}")
110
+
111
+ # The plan and the rate limit headers are GitHub's alone. A Gitea-compatible
112
+ # forge answers /user without either, and printing "-" and "?/? remaining"
113
+ # would read as a fault rather than as an absence.
114
+ if forge.is_github():
115
+ plan = (data.get("plan") or {}).get("name", "-")
116
+ click.echo(click.style("[✔] ", fg="green") + f"Plan: {plan}")
117
+ click.echo(
118
+ click.style("[✔] ", fg="green")
119
+ + f"Rate limit: {rate_remaining}/{rate_limit} remaining"
120
+ )
121
+
122
+ click.echo()
123
+ click.secho(f"Credentials for {forge_host} OK.", fg="green")
124
+
125
+
126
+ cli_command = check_github
@@ -5,32 +5,46 @@ import requests
5
5
  from splent_cli.commands.feature.feature_clone import feature_clone
6
6
  from splent_cli.utils.cache_utils import make_feature_writable
7
7
  from splent_cli.services import context
8
+ from splent_cli.utils import forge
8
9
  from splent_cli.utils.feature_utils import normalize_namespace
9
10
 
10
11
 
12
+ def _forge_label() -> str:
13
+ """How to name the forge in a message: the brand on GitHub, the host elsewhere."""
14
+ return "GitHub" if forge.is_github() else forge.host()
15
+
16
+
11
17
  @click.command(
12
18
  "feature:fork",
13
- short_help="Fork a feature on GitHub and clone it locally",
19
+ short_help="Fork a feature on the forge and clone it locally",
14
20
  )
15
21
  @click.argument("feature_name", required=True)
16
22
  @click.option(
17
23
  "--version", "-v", default="v1.0.0", help="Feature version (default: v1.0.0)"
18
24
  )
19
25
  def feature_fork(feature_name, version):
20
- token = os.getenv("GITHUB_TOKEN")
26
+ token = forge.token()
21
27
  github_user = os.getenv("GITHUB_USER")
22
28
 
23
29
  if not token or not github_user:
24
- click.secho("✖ Error: GITHUB_TOKEN and GITHUB_USER must be set", fg="red")
30
+ click.secho(
31
+ f"✖ Error: {forge.token_env_name()} and GITHUB_USER must be set", fg="red"
32
+ )
25
33
  raise SystemExit(1)
26
34
 
27
- upstream_owner = "splent-io"
28
- api_url = f"https://api.github.com/repos/{upstream_owner}/{feature_name}/forks"
35
+ upstream_owner = os.getenv("SPLENT_DEFAULT_ORG", "splent-io")
36
+ api_url = f"{forge.api_base()}/repos/{upstream_owner}/{feature_name}/forks"
29
37
  headers = {
30
38
  "Authorization": f"token {token}",
31
- "Accept": "application/vnd.github+json",
39
+ "Accept": (
40
+ "application/vnd.github+json" if forge.is_github() else "application/json"
41
+ ),
32
42
  }
33
43
 
44
+ # `default_branch_only` is a GitHub-only key. Gitea-compatible forges reject
45
+ # nothing but understand nothing either, so they get an empty body.
46
+ payload = {"default_branch_only": False} if forge.is_github() else {}
47
+
34
48
  click.secho(
35
49
  f"🔁 Forking {upstream_owner}/{feature_name} into {github_user}...", fg="cyan"
36
50
  )
@@ -38,17 +52,17 @@ def feature_fork(feature_name, version):
38
52
  resp = requests.post(
39
53
  api_url,
40
54
  headers=headers,
41
- json={"default_branch_only": False},
55
+ json=payload,
42
56
  timeout=30,
43
57
  )
44
58
  except requests.RequestException as e:
45
- click.secho(f"❌ Could not reach GitHub: {e}", fg="red")
59
+ click.secho(f"❌ Could not reach {_forge_label()}: {e}", fg="red")
46
60
  raise SystemExit(2)
47
61
 
48
62
  if resp.status_code in (403, 429):
49
63
  click.secho(
50
- "⚠ GitHub API rate limit or access denied. "
51
- "Set GITHUB_TOKEN to a token with repo scope and try again.",
64
+ f"⚠ {_forge_label()} API rate limit or access denied. "
65
+ f"Set {forge.token_env_name()} to a token with repo scope and try again.",
52
66
  fg="yellow",
53
67
  )
54
68
  if os.getenv("SPLENT_DEBUG"):
@@ -73,22 +87,24 @@ def feature_fork(feature_name, version):
73
87
  raise SystemExit(2)
74
88
  click.secho(f"🌐 Fork created: {fork_html_url}", fg="green")
75
89
 
76
- # Esperar a que GitHub lo procese
90
+ # Esperar a que la forja lo procese
77
91
  for i in range(5):
78
92
  try:
79
93
  r = requests.get(
80
- f"https://api.github.com/repos/{github_user}/{feature_name}",
94
+ f"{forge.api_base()}/repos/{github_user}/{feature_name}",
81
95
  headers=headers,
82
96
  timeout=30,
83
97
  )
84
98
  except requests.RequestException as e:
85
- click.secho(f"⌛ Waiting for GitHub to process fork... ({e})", fg="yellow")
99
+ click.secho(
100
+ f"⌛ Waiting for {_forge_label()} to process fork... ({e})", fg="yellow"
101
+ )
86
102
  time.sleep(3)
87
103
  continue
88
104
  if r.status_code == 200:
89
105
  click.secho("✅ Fork is ready.", fg="green")
90
106
  break
91
- click.secho("⌛ Waiting for GitHub to process fork...", fg="yellow")
107
+ click.secho(f"⌛ Waiting for {_forge_label()} to process fork...", fg="yellow")
92
108
  time.sleep(3)
93
109
  else:
94
110
  click.secho("⚠ Fork may still be processing.", fg="yellow")
@@ -138,7 +138,12 @@ def _extract_templates(src_dir: Path) -> list[str]:
138
138
 
139
139
 
140
140
  def _extract_template_hook_slots(src_dir: Path) -> list[str]:
141
- """Extract hook slot names declared in templates via get_template_hooks(...)."""
141
+ """Extract hook slot names declared in templates.
142
+
143
+ A template opens a slot either by iterating ``get_template_hooks(name)``
144
+ or by asking for the joined output with ``render_template_hooks(name)``
145
+ (the form used when the template keeps a fallback for an empty slot).
146
+ """
142
147
  templates_dir = src_dir / "templates"
143
148
  if not templates_dir.exists():
144
149
  return []
@@ -146,7 +151,9 @@ def _extract_template_hook_slots(src_dir: Path) -> list[str]:
146
151
  for html_file in templates_dir.rglob("*.html"):
147
152
  text = html_file.read_text()
148
153
  slots.update(
149
- re.findall(r"""get_template_hooks\s*\(\s*['"]([^'"]+)['"]""", text)
154
+ re.findall(
155
+ r"""(?:get|render)_template_hooks\s*\(\s*['"]([^'"]+)['"]""", text
156
+ )
150
157
  )
151
158
  return sorted(slots)
152
159
 
@@ -4,6 +4,7 @@ import tomllib
4
4
  import click
5
5
  import requests
6
6
  from splent_cli.services import context, compose
7
+ from splent_cli.utils import forge
7
8
  from splent_cli.utils.cache_utils import make_feature_writable
8
9
  from splent_cli.utils.proc import run
9
10
  from splent_cli.utils.io_utils import load_toml, atomic_write
@@ -62,6 +63,9 @@ def _git_out(path: str, *args) -> subprocess.CompletedProcess:
62
63
  def ensure_git_main(path: str, ns_git: str, name: str):
63
64
  from splent_cli.utils.git_url import build_git_url
64
65
 
66
+ # build_git_url() resolves the host and transport through the forge module,
67
+ # so rewriting origin here is also what repoints a checkout cloned from a
68
+ # previous forge at the one the workspace is configured for now.
65
69
  remote_url, _ = build_git_url(ns_git, name)
66
70
  r = _git_out(path, "remote", "get-url", "origin")
67
71
  if r.returncode == 0:
@@ -193,18 +197,20 @@ def _compile_assets(workspace: str, product_path: str, name: str):
193
197
  # =====================================================================
194
198
  def _warn_no_push_access(ns_git: str, name: str):
195
199
  """Print a warning if the user cannot push to the repo. Non-blocking."""
196
- token = os.getenv("GITHUB_TOKEN")
200
+ token = forge.token()
197
201
  if not token:
198
202
  return # no token = can't check, don't nag
199
203
 
200
204
  headers = {
201
- "Accept": "application/vnd.github+json",
205
+ "Accept": (
206
+ "application/vnd.github+json" if forge.is_github() else "application/json"
207
+ ),
202
208
  "Authorization": f"token {token}",
203
209
  "User-Agent": "splent-cli",
204
210
  }
205
211
  try:
206
212
  resp = requests.get(
207
- f"https://api.github.com/repos/{ns_git}/{name}",
213
+ f"{forge.api_base()}/repos/{ns_git}/{name}",
208
214
  headers=headers,
209
215
  timeout=5,
210
216
  )
@@ -644,6 +644,24 @@ def product_build(no_image, skip_preflight):
644
644
 
645
645
  click.echo(f"\n🐳 Building Docker image: {product}:{version}...")
646
646
 
647
+ # A feature that is not published to PyPI is installed from git
648
+ # inside the builder stage, and the URL for that is built from the
649
+ # forge settings. The build sees none of the workspace environment,
650
+ # so forward whichever of them is configured. The token is
651
+ # deliberately not forwarded: a build arg is recorded in the image
652
+ # metadata, so the repositories reached this way must be readable
653
+ # anonymously.
654
+ forge_args = []
655
+ for var in (
656
+ "SPLENT_FORGE_HOST",
657
+ "SPLENT_FORGE_SSH_HOST",
658
+ "SPLENT_FORGE_SSH_PORT",
659
+ "SPLENT_FORGE_API",
660
+ ):
661
+ value = os.getenv(var)
662
+ if value:
663
+ forge_args += ["--build-arg", f"{var}={value}"]
664
+
647
665
  try:
648
666
  subprocess.run(
649
667
  [
@@ -653,6 +671,7 @@ def product_build(no_image, skip_preflight):
653
671
  f"{product}:{version}",
654
672
  "-t",
655
673
  f"{product}:latest",
674
+ *forge_args,
656
675
  "-f",
657
676
  dockerfile,
658
677
  workspace,
@@ -1,9 +1,11 @@
1
1
  import click
2
2
 
3
+ from splent_cli.utils import forge
4
+
3
5
 
4
6
  @click.command(
5
7
  "tokens:setup",
6
- short_help="Print setup instructions for GitHub and PyPI tokens.",
8
+ short_help="Print setup instructions for the git forge and PyPI tokens.",
7
9
  )
8
10
  def tokens():
9
11
  """
@@ -14,21 +16,39 @@ def tokens():
14
16
  click.secho(" Required tokens for SPLENT", bold=True)
15
17
  click.echo(click.style(f" {'─' * 56}", fg="bright_black"))
16
18
 
17
- # ── GitHub ────────────────────────────────────────────────────────
19
+ # ── Forge ─────────────────────────────────────────────────────────
20
+ # The variable to set, the settings path and the scopes all depend on the
21
+ # forge this workspace points at, so the section is written from forge
22
+ # instead of from a github.com literal.
18
23
  click.echo()
19
- click.secho(" GITHUB_TOKEN", fg="cyan", bold=True)
24
+ click.secho(f" {forge.token_env_name()}", fg="cyan", bold=True)
20
25
  click.echo(" Used by: feature:release, feature:versions, feature:upgrade,")
21
26
  click.echo(" feature:search, check:github")
22
27
  click.echo()
23
28
  click.echo(" How to get it:")
24
- click.echo(" 1. Go to github.com → Settings → Developer settings")
25
- click.echo(" → Personal access tokens → Tokens (classic)")
26
- click.echo(" 2. Generate new token (classic)")
27
- click.echo(" 3. Enable scope: repo (full control of private repos)")
28
- click.echo(" 4. Copy the token (shown only once)")
29
- click.echo()
30
- click.secho(" Add to your .env:", fg="bright_black")
31
- click.echo(" GITHUB_TOKEN=ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxx")
29
+ if forge.is_github():
30
+ click.echo(" 1. Go to github.com → Settings → Developer settings")
31
+ click.echo(" → Personal access tokens → Tokens (classic)")
32
+ click.echo(" 2. Generate new token (classic)")
33
+ click.echo(" 3. Enable scope: repo (full control of private repos)")
34
+ click.echo(" 4. Copy the token (shown only once)")
35
+ click.echo()
36
+ click.secho(" Add to your .env:", fg="bright_black")
37
+ click.echo(f" {forge.token_env_name()}=ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxx")
38
+ else:
39
+ # Forgejo and Gitea keep tokens under Applications, and their scopes are
40
+ # per resource instead of GitHub's single 'repo'. Releasing a feature
41
+ # writes to a repository and, for an org-owned one, to the org itself.
42
+ click.echo(f" 1. Go to {forge.host()} → Settings → Applications")
43
+ click.echo(" → Access Tokens")
44
+ click.echo(" 2. Generate new token")
45
+ click.echo(" 3. Enable scopes: write:repository and write:organization")
46
+ click.echo(" 4. Copy the token (shown only once)")
47
+ click.echo()
48
+ click.secho(" Add to your .env:", fg="bright_black")
49
+ click.echo(
50
+ f" {forge.token_env_name()}=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
51
+ )
32
52
 
33
53
  # ── PyPI ──────────────────────────────────────────────────────────
34
54
  click.echo()
@@ -1,16 +1,24 @@
1
1
  """Ask the marketplace index to rebuild itself.
2
2
 
3
3
  The published index is what the marketplace serves, and it is built by a
4
- GitHub Actions workflow that runs on a push to its own repository, on a
5
- schedule, or on demand. A feature release or an SPL publication happens in
6
- a different repository, so neither of them used to reach it: the index
7
- caught up on the next cron run, hours later, and the only way to see a
8
- release in production sooner was to press the button by hand.
4
+ CI workflow that runs on a push to its own repository, on a schedule, or
5
+ on demand. A feature release or an SPL publication happens in a different
6
+ repository, so neither of them used to reach it: the index caught up on
7
+ the next cron run, hours later, and the only way to see a release in
8
+ production sooner was to press the button by hand.
9
9
 
10
10
  Releasing now asks for the rebuild as its last step. It is deliberately
11
11
  best effort: the release itself is already done and irreversible by then,
12
12
  so a token without workflow scope, or a network that is down, is reported
13
13
  and never turns a finished release into a failure.
14
+
15
+ Asking on demand is one POST to the workflow dispatch endpoint, which
16
+ GitHub and Gitea-compatible forges spell the same way and answer to the
17
+ same ``{"ref": ...}`` body. Only the headers differ, since GitHub's vendor
18
+ media type and API version pin mean nothing elsewhere and the credential
19
+ is read from the ``token`` scheme rather than ``Bearer``. A forge that
20
+ does not implement the endpoint answers 404, which is already handled the
21
+ same way as any other refusal.
14
22
  """
15
23
 
16
24
  import json
@@ -20,6 +28,8 @@ import urllib.request
20
28
 
21
29
  import click
22
30
 
31
+ from splent_cli.utils import forge
32
+
23
33
  INDEX_REPO = os.getenv("SPLENT_INDEX_REPO", "splent-io/splent_index")
24
34
  INDEX_WORKFLOW = os.getenv("SPLENT_INDEX_WORKFLOW", "build-index.yml")
25
35
  INDEX_REF = os.getenv("SPLENT_INDEX_REF", "main")
@@ -28,22 +38,46 @@ TIMEOUT_SECONDS = 15
28
38
 
29
39
  def _api_url() -> str:
30
40
  return (
31
- f"https://api.github.com/repos/{INDEX_REPO}"
41
+ f"{forge.api_base()}/repos/{INDEX_REPO}"
32
42
  f"/actions/workflows/{INDEX_WORKFLOW}/dispatches"
33
43
  )
34
44
 
35
45
 
46
+ def _headers(token: str) -> dict:
47
+ """Request headers in the forge's own spelling.
48
+
49
+ GitHub wants its vendor media type, its API version pin and a bearer
50
+ credential. A Gitea-compatible forge understands none of the three and
51
+ reads the credential from the ``token`` scheme, so it gets plain JSON.
52
+ """
53
+ if forge.is_github():
54
+ return {
55
+ "Accept": "application/vnd.github+json",
56
+ "Authorization": f"Bearer {token}",
57
+ "X-GitHub-Api-Version": "2022-11-28",
58
+ "Content-Type": "application/json",
59
+ "User-Agent": "splent-cli",
60
+ }
61
+ return {
62
+ "Accept": "application/json",
63
+ "Authorization": f"token {token}",
64
+ "Content-Type": "application/json",
65
+ "User-Agent": "splent-cli",
66
+ }
67
+
68
+
36
69
  def request_rebuild(*, quiet: bool = False) -> bool:
37
- """Trigger the index build workflow. True when GitHub accepted it.
70
+ """Trigger the index build workflow. True when the forge accepted it.
38
71
 
39
72
  Never raises: the caller has already published something.
40
73
  """
41
- token = os.getenv("GITHUB_TOKEN")
74
+ token = forge.token()
42
75
  if not token:
43
76
  if not quiet:
44
77
  click.secho(
45
- " index no GITHUB_TOKEN, so the marketplace index was not "
46
- "asked to rebuild. It will catch up on its own schedule.",
78
+ f" index no {forge.token_env_name()}, so the marketplace "
79
+ "index was not asked to rebuild. It will catch up on its own "
80
+ "schedule.",
47
81
  fg="yellow",
48
82
  )
49
83
  return False
@@ -52,13 +86,7 @@ def request_rebuild(*, quiet: bool = False) -> bool:
52
86
  _api_url(),
53
87
  data=json.dumps({"ref": INDEX_REF}).encode(),
54
88
  method="POST",
55
- headers={
56
- "Accept": "application/vnd.github+json",
57
- "Authorization": f"Bearer {token}",
58
- "X-GitHub-Api-Version": "2022-11-28",
59
- "Content-Type": "application/json",
60
- "User-Agent": "splent-cli",
61
- },
89
+ headers=_headers(token),
62
90
  )
63
91
 
64
92
  try:
@@ -66,11 +94,13 @@ def request_rebuild(*, quiet: bool = False) -> bool:
66
94
  accepted = response.status in (200, 201, 204)
67
95
  except urllib.error.HTTPError as error:
68
96
  if not quiet:
69
- hint = (
70
- " The token needs the workflow scope."
71
- if error.code in (403, 404)
72
- else ""
73
- )
97
+ hint = ""
98
+ if error.code in (403, 404):
99
+ hint = (
100
+ " The token needs the workflow scope."
101
+ if forge.is_github()
102
+ else " The token needs write access to the index repository."
103
+ )
74
104
  click.secho(
75
105
  f" index the marketplace index refused the rebuild "
76
106
  f"({error.code}).{hint} It will catch up on its own schedule.",
@@ -80,8 +110,8 @@ def request_rebuild(*, quiet: bool = False) -> bool:
80
110
  except Exception:
81
111
  if not quiet:
82
112
  click.secho(
83
- " index could not reach GitHub to rebuild the marketplace "
84
- "index. It will catch up on its own schedule.",
113
+ f" index could not reach {forge.host()} to rebuild the "
114
+ "marketplace index. It will catch up on its own schedule.",
85
115
  fg="yellow",
86
116
  )
87
117
  return False