splent-cli 1.10.0__tar.gz → 1.11.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 (170) hide show
  1. {splent_cli-1.10.0/src/splent_cli.egg-info → splent_cli-1.11.0}/PKG-INFO +1 -1
  2. {splent_cli-1.10.0 → splent_cli-1.11.0}/pyproject.toml +6 -3
  3. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/check/check_infra.py +4 -12
  4. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/database/db_migrate.py +1 -3
  5. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/database/db_seed.py +1 -3
  6. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/doctor.py +3 -1
  7. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/feature/feature_clone.py +46 -99
  8. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/feature/feature_compile.py +1 -3
  9. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/feature/feature_env.py +1 -3
  10. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/feature/feature_install.py +21 -28
  11. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/feature/feature_refine.py +2 -5
  12. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/feature/feature_release.py +8 -1
  13. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/feature/feature_search.py +2 -6
  14. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/feature/feature_upgrade.py +30 -14
  15. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/lint.py +3 -1
  16. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/locust.py +2 -6
  17. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/product/product_clean.py +3 -1
  18. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/product/product_create.py +1 -7
  19. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/product/product_env.py +1 -1
  20. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/product/product_release.py +8 -1
  21. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/product/product_run.py +3 -1
  22. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/product/product_up.py +14 -3
  23. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/release/release_core.py +26 -4
  24. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/spl/spl_add_feature.py +1 -3
  25. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/uvl/uvl_utils.py +1 -3
  26. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/services/release.py +112 -1
  27. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/utils/dynamic_imports.py +1 -3
  28. splent_cli-1.11.0/src/splent_cli/utils/git_url.py +221 -0
  29. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/utils/integrity.py +4 -1
  30. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/utils/io_utils.py +3 -1
  31. {splent_cli-1.10.0 → splent_cli-1.11.0/src/splent_cli.egg-info}/PKG-INFO +1 -1
  32. splent_cli-1.10.0/src/splent_cli/utils/git_url.py +0 -82
  33. {splent_cli-1.10.0 → splent_cli-1.11.0}/LICENSE +0 -0
  34. {splent_cli-1.10.0 → splent_cli-1.11.0}/README.md +0 -0
  35. {splent_cli-1.10.0 → splent_cli-1.11.0}/setup.cfg +0 -0
  36. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/__init__.py +0 -0
  37. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/__main__.py +0 -0
  38. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/cli.py +0 -0
  39. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/__init__.py +0 -0
  40. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/cache/__init__.py +0 -0
  41. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/cache/cache_clear.py +0 -0
  42. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/cache/cache_orphans.py +0 -0
  43. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/cache/cache_outdated.py +0 -0
  44. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/cache/cache_prune.py +0 -0
  45. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/cache/cache_size.py +0 -0
  46. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/cache/cache_status.py +0 -0
  47. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/cache/cache_usage.py +0 -0
  48. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/cache/cache_versions.py +0 -0
  49. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/check/__init__.py +0 -0
  50. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/check/check_deps.py +0 -0
  51. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/check/check_docker.py +0 -0
  52. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/check/check_env.py +0 -0
  53. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/check/check_features.py +0 -0
  54. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/check/check_github.py +0 -0
  55. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/check/check_product.py +0 -0
  56. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/check/check_pypi.py +0 -0
  57. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/check/check_pyproject.py +0 -0
  58. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/clear/__init__.py +0 -0
  59. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/clear/clear_build.py +0 -0
  60. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/clear/clear_log.py +0 -0
  61. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/clear/clear_uploads.py +0 -0
  62. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/command/__init__.py +0 -0
  63. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/command/command_create.py +0 -0
  64. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/coverage.py +0 -0
  65. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/database/db_console.py +0 -0
  66. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/database/db_dump.py +0 -0
  67. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/database/db_reset.py +0 -0
  68. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/database/db_restore.py +0 -0
  69. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/database/db_rollback.py +0 -0
  70. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/database/db_status.py +0 -0
  71. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/database/db_upgrade.py +0 -0
  72. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/env/env_list.py +0 -0
  73. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/env/env_set.py +0 -0
  74. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/env/env_show.py +0 -0
  75. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/export/__init__.py +0 -0
  76. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/export/export_puml.py +0 -0
  77. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/feature/feature_add.py +0 -0
  78. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/feature/feature_attach.py +0 -0
  79. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/feature/feature_clean.py +0 -0
  80. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/feature/feature_compat.py +0 -0
  81. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/feature/feature_contract.py +0 -0
  82. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/feature/feature_create.py +0 -0
  83. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/feature/feature_delete.py +0 -0
  84. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/feature/feature_detach.py +0 -0
  85. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/feature/feature_discard.py +0 -0
  86. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/feature/feature_drift.py +0 -0
  87. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/feature/feature_fork.py +0 -0
  88. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/feature/feature_git.py +0 -0
  89. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/feature/feature_hook_add.py +0 -0
  90. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/feature/feature_hook_remove.py +0 -0
  91. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/feature/feature_hooks.py +0 -0
  92. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/feature/feature_impact.py +0 -0
  93. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/feature/feature_inject_config.py +0 -0
  94. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/feature/feature_list.py +0 -0
  95. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/feature/feature_order.py +0 -0
  96. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/feature/feature_outdated.py +0 -0
  97. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/feature/feature_pin.py +0 -0
  98. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/feature/feature_pip_install.py +0 -0
  99. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/feature/feature_pull.py +0 -0
  100. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/feature/feature_remove.py +0 -0
  101. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/feature/feature_rename.py +0 -0
  102. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/feature/feature_status.py +0 -0
  103. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/feature/feature_sync_template.py +0 -0
  104. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/feature/feature_test.py +0 -0
  105. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/feature/feature_translate.py +0 -0
  106. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/feature/feature_unlock.py +0 -0
  107. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/feature/feature_versions.py +0 -0
  108. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/feature/feature_xray.py +0 -0
  109. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/product/__init__.py +0 -0
  110. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/product/product_auto_require.py +0 -0
  111. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/product/product_build.py +0 -0
  112. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/product/product_commands.py +0 -0
  113. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/product/product_config.py +0 -0
  114. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/product/product_configure.py +0 -0
  115. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/product/product_console.py +0 -0
  116. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/product/product_containers.py +0 -0
  117. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/product/product_deploy.py +0 -0
  118. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/product/product_derive.py +0 -0
  119. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/product/product_deselect.py +0 -0
  120. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/product/product_down.py +0 -0
  121. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/product/product_drift.py +0 -0
  122. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/product/product_list.py +0 -0
  123. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/product/product_logs.py +0 -0
  124. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/product/product_missing.py +0 -0
  125. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/product/product_port.py +0 -0
  126. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/product/product_resolve.py +0 -0
  127. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/product/product_restart.py +0 -0
  128. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/product/product_routes.py +0 -0
  129. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/product/product_select.py +0 -0
  130. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/product/product_shell.py +0 -0
  131. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/product/product_signals.py +0 -0
  132. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/product/product_sync_template.py +0 -0
  133. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/product/product_test.py +0 -0
  134. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/product/product_validate.py +0 -0
  135. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/release/__init__.py +0 -0
  136. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/selenium.py +0 -0
  137. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/spl/__init__.py +0 -0
  138. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/spl/spl_add_constraints.py +0 -0
  139. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/spl/spl_configurations.py +0 -0
  140. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/spl/spl_create.py +0 -0
  141. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/spl/spl_deps.py +0 -0
  142. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/spl/spl_features.py +0 -0
  143. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/spl/spl_fetch.py +0 -0
  144. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/spl/spl_info.py +0 -0
  145. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/spl/spl_list.py +0 -0
  146. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/spl/spl_utils.py +0 -0
  147. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/tokens_setup.py +0 -0
  148. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/commands/version.py +0 -0
  149. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/services/__init__.py +0 -0
  150. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/services/compose.py +0 -0
  151. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/services/context.py +0 -0
  152. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/services/preflight.py +0 -0
  153. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/utils/__init__.py +0 -0
  154. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/utils/cache_utils.py +0 -0
  155. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/utils/command_loader.py +0 -0
  156. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/utils/contract_freshness.py +0 -0
  157. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/utils/db_utils.py +0 -0
  158. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/utils/decorators.py +0 -0
  159. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/utils/feature_installer.py +0 -0
  160. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/utils/feature_utils.py +0 -0
  161. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/utils/lifecycle.py +0 -0
  162. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/utils/manifest.py +0 -0
  163. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/utils/path_utils.py +0 -0
  164. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/utils/proc.py +0 -0
  165. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli/utils/template_drift.py +0 -0
  166. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli.egg-info/SOURCES.txt +0 -0
  167. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli.egg-info/dependency_links.txt +0 -0
  168. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli.egg-info/entry_points.txt +0 -0
  169. {splent_cli-1.10.0 → splent_cli-1.11.0}/src/splent_cli.egg-info/requires.txt +0 -0
  170. {splent_cli-1.10.0 → splent_cli-1.11.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.10.0
3
+ Version: 1.11.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.10.0"
7
+ version = "1.11.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"
@@ -63,8 +63,11 @@ where = ["src"]
63
63
  testpaths = ["tests"]
64
64
  pythonpath = ["src"]
65
65
 
66
- [tool.black]
67
- line-length = 79
66
+ # Canonical formatter/linter is Ruff (`splent lint` runs `ruff check` +
67
+ # `ruff format`). Ruff's default line length (88) is the project standard;
68
+ # set explicitly here so it is unambiguous.
69
+ [tool.ruff]
70
+ line-length = 88
68
71
 
69
72
  [project.urls]
70
73
  Homepage = "https://github.com/diverso-lab/splent_cli"
@@ -209,9 +209,7 @@ def check_infra():
209
209
  click.echo(click.style(" Networks", bold=True))
210
210
  required_networks: set[str] = set()
211
211
  for label, cf in compose_files:
212
- result = _run(
213
- ["docker", "compose", "-f", cf, "config", "--format", "json"]
214
- )
212
+ result = _run(["docker", "compose", "-f", cf, "config", "--format", "json"])
215
213
  if result.returncode != 0:
216
214
  continue
217
215
  try:
@@ -242,9 +240,7 @@ def check_infra():
242
240
  build_count = 0
243
241
  for label, cf in compose_files:
244
242
  docker_dir = os.path.dirname(cf)
245
- result = _run(
246
- ["docker", "compose", "-f", cf, "config", "--format", "json"]
247
- )
243
+ result = _run(["docker", "compose", "-f", cf, "config", "--format", "json"])
248
244
  if result.returncode != 0:
249
245
  continue
250
246
  try:
@@ -282,9 +278,7 @@ def check_infra():
282
278
  services_depended_on: dict[str, str] = {} # depended_svc -> by_svc
283
279
 
284
280
  for label, cf in compose_files:
285
- result = _run(
286
- ["docker", "compose", "-f", cf, "config", "--format", "json"]
287
- )
281
+ result = _run(["docker", "compose", "-f", cf, "config", "--format", "json"])
288
282
  if result.returncode != 0:
289
283
  continue
290
284
  try:
@@ -321,9 +315,7 @@ def check_infra():
321
315
  click.echo(click.style(" Volumes", bold=True))
322
316
  all_volumes: dict[str, list[str]] = {} # vol_name -> [labels]
323
317
  for label, cf in compose_files:
324
- result = _run(
325
- ["docker", "compose", "-f", cf, "config", "--format", "json"]
326
- )
318
+ result = _run(["docker", "compose", "-f", cf, "config", "--format", "json"])
327
319
  if result.returncode != 0:
328
320
  continue
329
321
  try:
@@ -75,9 +75,7 @@ def db_migrate(feature, message, empty):
75
75
  and kept so you can write ``upgrade()``/``downgrade()`` by hand.
76
76
  """
77
77
  if empty and not feature:
78
- click.echo(
79
- click.style("❌ --empty requires a FEATURE argument.", fg="red")
80
- )
78
+ click.echo(click.style("❌ --empty requires a FEATURE argument.", fg="red"))
81
79
  raise SystemExit(1)
82
80
 
83
81
  if feature:
@@ -179,9 +179,7 @@ def db_seed(reset, yes, module):
179
179
  break
180
180
  except Exception as e:
181
181
  click.echo(
182
- click.style(
183
- f"❌ Error in {seeder.__class__.__name__}: {e}", fg="red"
184
- )
182
+ click.style(f"❌ Error in {seeder.__class__.__name__}: {e}", fg="red")
185
183
  )
186
184
  success = False
187
185
  break
@@ -68,7 +68,9 @@ def _check_workspace_precondition():
68
68
  wd = os.getenv("WORKING_DIR")
69
69
  workspace = wd or os.getcwd()
70
70
  if not wd:
71
- problems.append("WORKING_DIR is not set (falling back to the current directory)")
71
+ problems.append(
72
+ "WORKING_DIR is not set (falling back to the current directory)"
73
+ )
72
74
  elif not os.path.isdir(wd):
73
75
  problems.append(f"WORKING_DIR points to a missing directory: {wd}")
74
76
 
@@ -6,7 +6,7 @@ import click
6
6
  from splent_cli.services import context
7
7
  from splent_cli.utils.cache_utils import make_feature_readonly
8
8
  from splent_cli.utils.feature_utils import normalize_namespace
9
- from splent_cli.utils.proc import run, require_tool
9
+ from splent_cli.utils.proc import require_tool
10
10
 
11
11
 
12
12
  DEFAULT_NAMESPACE = os.getenv("SPLENT_DEFAULT_NAMESPACE", "splent_io")
@@ -20,8 +20,15 @@ DEFAULT_NAMESPACE = os.getenv("SPLENT_DEFAULT_NAMESPACE", "splent_io")
20
20
  def _get_latest_tag(namespace, repo) -> str | None:
21
21
  """Fetch the highest semver tag from GitHub. Returns None if unreachable or no tags."""
22
22
  api_url = f"https://api.github.com/repos/{namespace}/{repo}/tags?per_page=100"
23
+ # Authenticate when a token is present so version resolution also works for
24
+ # PRIVATE feature repos (an unauthenticated call 404s on those) and to raise
25
+ # the API rate limit.
26
+ headers = {}
27
+ token = os.getenv("GITHUB_TOKEN")
28
+ if token:
29
+ headers["Authorization"] = f"Bearer {token}"
23
30
  try:
24
- r = requests.get(api_url, timeout=5)
31
+ r = requests.get(api_url, headers=headers, timeout=5)
25
32
  r.raise_for_status()
26
33
  tags = r.json()
27
34
  if not tags:
@@ -42,16 +49,6 @@ def _get_latest_tag(namespace, repo) -> str | None:
42
49
  return None
43
50
 
44
51
 
45
- def _build_repo_url(namespace, repo):
46
- """Build the Git URL, trying SSH first with HTTPS fallback.
47
-
48
- Returns a tuple (real_url, display_url) where display_url never contains a token.
49
- """
50
- from splent_cli.utils.git_url import build_git_url
51
-
52
- return build_git_url(namespace, repo)
53
-
54
-
55
52
  def _parse_full_name(full_name: str):
56
53
  """
57
54
  full_name = <namespace>/<repo>[@version]
@@ -115,9 +112,6 @@ def feature_clone(full_name):
115
112
  )
116
113
  raise SystemExit(1)
117
114
 
118
- # Build Git URL based on your ownership
119
- fork_url, display_url = _build_repo_url(namespace, repo)
120
-
121
115
  # Local destination
122
116
  namespace_safe = normalize_namespace(namespace)
123
117
  workspace = str(context.workspace())
@@ -137,98 +131,51 @@ def feature_clone(full_name):
137
131
  "Install Git from https://git-scm.com/downloads and make sure it is on your PATH.",
138
132
  )
139
133
 
140
- click.secho(f"⬇️ Cloning {display_url}@{version}", fg="cyan")
141
-
142
- # Try clone the specific tag/branch (suppress git noise). Capture output so
143
- # we can tell WHY it failed instead of blindly assuming "version not found".
144
- result = run(
145
- [
146
- "git",
147
- "-c",
148
- "advice.detachedHead=false",
149
- "clone",
150
- "--depth",
151
- "1",
152
- "--branch",
153
- version,
154
- "--quiet",
155
- fork_url,
156
- local_path,
157
- ],
158
- check=False,
159
- capture=True,
134
+ from splent_cli.utils.git_url import (
135
+ clone as git_clone,
136
+ CLONE_SUCCESS,
137
+ CLONE_REF_NOT_FOUND,
160
138
  )
161
139
 
162
- if result.returncode != 0:
163
- shutil.rmtree(local_path, ignore_errors=True)
164
- stderr = (result.stderr or result.stdout or "").strip()
165
- stderr_lc = stderr.lower()
166
-
167
- # A genuinely missing ref is the ONLY case where falling back to main is
168
- # correct. git reports it as e.g.:
169
- # "Remote branch <x> not found in upstream origin"
170
- # "Could not find remote branch <x> to clone"
171
- ref_not_found = (
172
- "remote branch" in stderr_lc and "not found" in stderr_lc
173
- ) or "could not find remote branch" in stderr_lc
174
-
175
- # Auth / network / repo-access failures must NOT silently install main.
176
- auth_or_network = any(
177
- token in stderr_lc
178
- for token in (
179
- "authentication failed",
180
- "permission denied",
181
- "could not read from remote repository",
182
- "repository not found",
183
- "could not resolve host",
184
- "connection timed out",
185
- "connection refused",
186
- "network is unreachable",
187
- "failed to connect",
188
- "ssl",
189
- "tls",
190
- )
140
+ click.secho(f"⬇️ Cloning {namespace}/{repo}@{version}", fg="cyan")
141
+
142
+ # Always try SSH first, then HTTPS (GITHUB_TOKEN if set, else anonymous). The
143
+ # transport is decided per repo from the real clone result (see
144
+ # git_url.clone), so a working SSH key that simply can't read THIS repo no
145
+ # longer blocks the HTTPS path.
146
+ outcome, used_url, stderr = git_clone(namespace, repo, local_path, ref=version)
147
+
148
+ # A genuinely missing tag/branch is the ONLY case where falling back to the
149
+ # default branch is correct (the repo itself was reachable).
150
+ if outcome == CLONE_REF_NOT_FOUND:
151
+ click.secho(
152
+ f"⚠️ Version '{version}' not found. Cloning default branch instead.",
153
+ fg="yellow",
191
154
  )
155
+ outcome, used_url, stderr = git_clone(namespace, repo, local_path, ref=None)
192
156
 
193
- if ref_not_found and not auth_or_network:
194
- click.secho(
195
- f"⚠️ Version '{version}' not found. Cloning main instead.", fg="yellow"
196
- )
197
- fallback = run(
198
- ["git", "clone", "--depth", "1", "--quiet", fork_url, local_path],
199
- check=False,
200
- capture=True,
201
- )
202
- if fallback.returncode != 0:
203
- shutil.rmtree(local_path, ignore_errors=True)
204
- detail = (fallback.stderr or fallback.stdout or "").strip()
205
- click.secho(
206
- f"❌ Repository '{namespace}/{repo}' not found or not accessible.",
207
- fg="red",
208
- )
209
- if detail:
210
- click.secho(detail, fg="red")
211
- raise SystemExit(1)
212
- else:
213
- # Network / auth / unknown git failure: do NOT fall back to main,
214
- # which would silently install the wrong (unpinned) code.
215
- click.secho(
216
- f"❌ Failed to clone '{namespace}/{repo}@{version}'.", fg="red"
217
- )
218
- click.secho(
219
- "This looks like a network, authentication, or repository-access "
220
- "problem rather than a missing version. Check your connection and "
221
- "credentials, then try again.",
222
- fg="red",
223
- )
224
- if stderr:
225
- click.secho(stderr, fg="red")
226
- raise SystemExit(1)
157
+ if outcome != CLONE_SUCCESS:
158
+ shutil.rmtree(local_path, ignore_errors=True)
159
+ click.secho(
160
+ f"❌ Repository '{namespace}/{repo}' not found or not accessible "
161
+ "(tried SSH and HTTPS).",
162
+ fg="red",
163
+ )
164
+ click.secho(
165
+ "Check your network, that the repo exists, and that you have read "
166
+ "access an SSH key authorised for the repo, or a GITHUB_TOKEN with "
167
+ "read scope in your .env.",
168
+ fg="red",
169
+ )
170
+ if stderr:
171
+ click.secho(stderr, fg="red")
172
+ raise SystemExit(1)
227
173
 
228
174
  # Lock files as read-only to prevent accidental edits on pinned features
229
175
  make_feature_readonly(local_path)
230
176
 
231
177
  click.secho(
232
- f"✅ Feature '{namespace}/{repo}@{version}' cloned successfully.", fg="green"
178
+ f"✅ Feature '{namespace}/{repo}@{version}' cloned successfully ({used_url}).",
179
+ fg="green",
233
180
  )
234
181
  click.secho(f"🔒 Cached (read-only) at: {local_path}", fg="blue")
@@ -157,9 +157,7 @@ def _compile_in_container(container_id, feature, watch, production, workspace, p
157
157
  raise click.ClickException(
158
158
  f"'{run_cmd[0]}' is not installed or not on PATH.\n{tool_hint}"
159
159
  )
160
- click.echo(
161
- click.style(f"👀 Watching {feature} in {mode} mode...", fg="blue")
162
- )
160
+ click.echo(click.style(f"👀 Watching {feature} in {mode} mode...", fg="blue"))
163
161
  else:
164
162
  result = run(run_cmd, check=False, tool_hint=tool_hint)
165
163
  if result.returncode != 0:
@@ -121,9 +121,7 @@ def feature_env(feature_name, generate, env_name):
121
121
  try:
122
122
  shutil.copy(selected, env_file)
123
123
  except OSError as exc:
124
- click.echo(
125
- f"❌ Failed to create {env_file} from {selected}: {exc}"
126
- )
124
+ click.echo(f"❌ Failed to create {env_file} from {selected}: {exc}")
127
125
  raise SystemExit(1)
128
126
  click.echo(
129
127
  f"📄 Created {feature_entry}/docker/.env from {os.path.basename(selected)}"
@@ -241,7 +241,8 @@ def feature_install(feature_identifier, env_scope, mode, version):
241
241
  )
242
242
  if result.returncode != 0:
243
243
  click.secho(
244
- f" Clone failed: {(result.stderr or '').strip()}", fg="red"
244
+ f" Clone failed: {(result.stderr or '').strip()}",
245
+ fg="red",
245
246
  )
246
247
  raise SystemExit(1)
247
248
  else:
@@ -291,9 +292,7 @@ def feature_install(feature_identifier, env_scope, mode, version):
291
292
  check=False,
292
293
  )
293
294
  if dep.returncode != 0:
294
- click.secho(
295
- f" Installing dependency {m} failed.", fg="red"
296
- )
295
+ click.secho(f" Installing dependency {m} failed.", fg="red")
297
296
  raise SystemExit(1)
298
297
 
299
298
  # Attach to product
@@ -315,32 +314,27 @@ def feature_install(feature_identifier, env_scope, mode, version):
315
314
  # Clone to workspace root as editable
316
315
  click.echo(click.style(" clone ", dim=True) + f"{short} (editable)")
317
316
  from splent_cli.commands.feature.feature_clone import (
318
- _build_repo_url,
319
317
  _get_latest_tag,
320
318
  )
319
+ from splent_cli.utils.git_url import (
320
+ clone as git_clone,
321
+ CLONE_SUCCESS,
322
+ CLONE_REF_NOT_FOUND,
323
+ )
321
324
 
325
+ # SSH first, then HTTPS (per repo). ref=tag (None → default branch).
322
326
  tag = _get_latest_tag(namespace_github, feature_name)
323
- repo_url, _ = _build_repo_url(namespace_github, feature_name)
324
- branch = tag or "main"
325
- clone = run(
326
- [
327
- "git",
328
- "clone",
329
- "--depth",
330
- "1",
331
- "--branch",
332
- branch,
333
- "--quiet",
334
- repo_url,
335
- feature_dir,
336
- ],
337
- check=False,
338
- capture=True,
327
+ outcome, _used, err = git_clone(
328
+ namespace_github, feature_name, feature_dir, ref=tag
339
329
  )
340
- if clone.returncode != 0:
330
+ if outcome == CLONE_REF_NOT_FOUND:
331
+ outcome, _used, err = git_clone(
332
+ namespace_github, feature_name, feature_dir, ref=None
333
+ )
334
+ if outcome != CLONE_SUCCESS:
341
335
  click.secho(
342
- f" Could not clone {namespace_github}/{feature_name}: "
343
- f"{(clone.stderr or '').strip()}",
336
+ f" Could not clone {namespace_github}/{feature_name} "
337
+ f"(tried SSH and HTTPS): {err}",
344
338
  fg="red",
345
339
  )
346
340
  raise SystemExit(1)
@@ -386,9 +380,7 @@ def feature_install(feature_identifier, env_scope, mode, version):
386
380
  check=False,
387
381
  )
388
382
  if dep.returncode != 0:
389
- click.secho(
390
- f" Installing dependency {m} failed.", fg="red"
391
- )
383
+ click.secho(f" Installing dependency {m} failed.", fg="red")
392
384
  raise SystemExit(1)
393
385
 
394
386
  # Add to product
@@ -454,7 +446,8 @@ def feature_install(feature_identifier, env_scope, mode, version):
454
446
  )
455
447
  if result.returncode != 0:
456
448
  click.secho(
457
- f" Docker failed: {(result.stderr or '').strip()}", fg="yellow"
449
+ f" Docker failed: {(result.stderr or '').strip()}",
450
+ fg="yellow",
458
451
  )
459
452
 
460
453
  click.echo()
@@ -364,9 +364,7 @@ def _scaffold_service(
364
364
  repos_path = os.path.join(
365
365
  feature_path, "src", ns_safe, feature_name, "repositories.py"
366
366
  )
367
- if os.path.isfile(repos_path) and _confirm_overwrite(
368
- repos_path, "repositories.py"
369
- ):
367
+ if os.path.isfile(repos_path) and _confirm_overwrite(repos_path, "repositories.py"):
370
368
  with open(repos_path, "w") as f:
371
369
  f.write(
372
370
  "# Refinement features do not need their own repository.\n"
@@ -875,8 +873,7 @@ def feature_refinement(refiner_name):
875
873
  tomllib.loads(content)
876
874
  except tomllib.TOMLDecodeError as e:
877
875
  click.secho(
878
- f" Refusing to write pyproject.toml: the result is not valid TOML.\n"
879
- f" {e}",
876
+ f" Refusing to write pyproject.toml: the result is not valid TOML.\n {e}",
880
877
  fg="red",
881
878
  )
882
879
  raise SystemExit(1)
@@ -555,8 +555,13 @@ def create_versioned_snapshot(namespace, feature_name, version, workspace):
555
555
  @click.argument("feature_ref")
556
556
  @click.argument("version", required=False, default=None)
557
557
  @click.option("--attach", is_flag=True)
558
+ @click.option(
559
+ "--skip-checks",
560
+ is_flag=True,
561
+ help="Skip the pre-release lint + tests gate (emergencies only).",
562
+ )
558
563
  @context.requires_product
559
- def feature_release(feature_ref, version, attach):
564
+ def feature_release(feature_ref, version, attach, skip_checks):
560
565
  workspace = str(context.workspace())
561
566
 
562
567
  feature_path, namespace, feature_name = resolve_feature_path(feature_ref, workspace)
@@ -583,6 +588,8 @@ def feature_release(feature_ref, version, attach):
583
588
  f"{namespace}/{feature_name}",
584
589
  feature_path,
585
590
  version,
591
+ kind="feature",
592
+ skip_checks=skip_checks,
586
593
  pre_commit_hook=_pre_commit,
587
594
  post_pypi_hook=_post_pypi,
588
595
  )
@@ -23,18 +23,14 @@ def _github_request(url: str, token: str | None) -> dict | list | None:
23
23
  if e.code in (403, 429):
24
24
  remaining = e.headers.get("X-RateLimit-Remaining") if e.headers else None
25
25
  if e.code == 429 or remaining == "0":
26
- click.secho(
27
- "❌ GitHub API rate limit exceeded.", fg="red"
28
- )
26
+ click.secho("❌ GitHub API rate limit exceeded.", fg="red")
29
27
  if not token:
30
28
  click.secho(
31
29
  "💡 Set GITHUB_TOKEN to raise your rate limit and access private repos.",
32
30
  fg="yellow",
33
31
  )
34
32
  raise SystemExit(1)
35
- click.secho(
36
- f"❌ GitHub API access forbidden (HTTP {e.code}).", fg="red"
37
- )
33
+ click.secho(f"❌ GitHub API access forbidden (HTTP {e.code}).", fg="red")
38
34
  if not token:
39
35
  click.secho(
40
36
  "💡 Set GITHUB_TOKEN to access private repos and raise rate limits.",
@@ -9,8 +9,10 @@ import click
9
9
  from packaging.version import Version, InvalidVersion
10
10
 
11
11
  from splent_cli.services import context
12
- from splent_cli.utils.feature_utils import normalize_namespace, read_features_from_data
13
- from splent_cli.utils.proc import run
12
+ from splent_cli.utils.feature_utils import (
13
+ normalize_namespace,
14
+ read_features_from_data,
15
+ )
14
16
 
15
17
 
16
18
  # ── GitHub helpers ────────────────────────────────────────────────────────────
@@ -82,13 +84,22 @@ def _read_features(pyproject_path: Path) -> list[dict]:
82
84
  else:
83
85
  name, version = rest, None
84
86
  result.append(
85
- {"name": name, "version": version, "ns_github": ns_github, "ns_fs": ns_fs}
87
+ {
88
+ "name": name,
89
+ "version": version,
90
+ "ns_github": ns_github,
91
+ "ns_fs": ns_fs,
92
+ }
86
93
  )
87
94
  return result
88
95
 
89
96
 
90
97
  def _update_pyproject(
91
- pyproject_path: Path, ns_github: str, name: str, old_ver: str | None, new_ver: str
98
+ pyproject_path: Path,
99
+ ns_github: str,
100
+ name: str,
101
+ old_ver: str | None,
102
+ new_ver: str,
92
103
  ):
93
104
  content = pyproject_path.read_text()
94
105
  if old_ver:
@@ -109,16 +120,16 @@ def _clone_if_missing(ns_fs: str, name: str, version: str, cache_root: Path):
109
120
  if target.exists():
110
121
  return
111
122
  ns_github = ns_fs.replace("_", "-")
112
- from splent_cli.utils.git_url import build_git_url
123
+ from splent_cli.utils.git_url import clone as git_clone, CLONE_SUCCESS
113
124
 
114
- url, _ = build_git_url(ns_github, name)
115
125
  click.echo(f" ⬇️ Cloning {ns_fs}/{name}@{version}...")
116
- run(
117
- ["git", "clone", "--branch", version, "--depth", "1", url, str(target)],
118
- check=True,
119
- capture=True,
120
- tool_hint="Install git: https://git-scm.com/downloads",
121
- )
126
+ # SSH first, then HTTPS. A pinned version that doesn't exist stays an error
127
+ # here upgrade must not silently fall back to a different ref.
128
+ outcome, _used, err = git_clone(ns_github, name, str(target), ref=version)
129
+ if outcome != CLONE_SUCCESS:
130
+ raise click.ClickException(
131
+ f"Could not clone {ns_fs}/{name}@{version} (tried SSH and HTTPS). {err}".strip()
132
+ )
122
133
  from splent_cli.utils.cache_utils import make_feature_readonly
123
134
 
124
135
  make_feature_readonly(str(target))
@@ -242,7 +253,11 @@ def feature_upgrade(feature_ref, yes):
242
253
  try:
243
254
  _clone_if_missing(u["ns_fs"], u["name"], u["latest"], cache_root)
244
255
  _update_pyproject(
245
- pyproject_path, u["ns_github"], u["name"], u["version"], u["latest"]
256
+ pyproject_path,
257
+ u["ns_github"],
258
+ u["name"],
259
+ u["version"],
260
+ u["latest"],
246
261
  )
247
262
  _update_symlink(
248
263
  product_path,
@@ -258,7 +273,8 @@ def feature_upgrade(feature_ref, yes):
258
273
 
259
274
  click.echo()
260
275
  click.secho(
261
- " Done. Run 'splent product:resolve' to reinstall pip dependencies.", fg="cyan"
276
+ " Done. Run 'splent product:resolve' to reinstall pip dependencies.",
277
+ fg="cyan",
262
278
  )
263
279
  click.echo()
264
280
 
@@ -72,7 +72,9 @@ def linter(fix, targets):
72
72
  label = f"{'Fixing' if fix else 'Checking'} {directory}"
73
73
  click.echo(click.style(f"🔍 {label}...\n", fg="yellow"))
74
74
 
75
- result = run(lint_cmd + [directory], check=False, capture=True, tool_hint=_RUFF_HINT)
75
+ result = run(
76
+ lint_cmd + [directory], check=False, capture=True, tool_hint=_RUFF_HINT
77
+ )
76
78
 
77
79
  output = (result.stdout + result.stderr).strip()
78
80
  if result.returncode != 0:
@@ -179,9 +179,7 @@ def locust(module):
179
179
  try:
180
180
  client = docker.from_env()
181
181
  except docker.errors.DockerException as e:
182
- raise click.ClickException(
183
- f"Could not connect to the Docker daemon: {e}"
184
- )
182
+ raise click.ClickException(f"Could not connect to the Docker daemon: {e}")
185
183
 
186
184
  try:
187
185
  web_container = client.containers.get("web_app_container")
@@ -247,9 +245,7 @@ def stop():
247
245
  try:
248
246
  os.kill(proc.pid, signal.SIGTERM)
249
247
  except (ProcessLookupError, PermissionError) as e:
250
- click.secho(
251
- f"⚠️ Could not stop PID {proc.pid}: {e}", fg="yellow"
252
- )
248
+ click.secho(f"⚠️ Could not stop PID {proc.pid}: {e}", fg="yellow")
253
249
 
254
250
  def stop_docker_locust():
255
251
  click.echo("Stopping Locust container if it is running...")
@@ -55,7 +55,9 @@ def product_clean(env_dev, env_prod, yes):
55
55
  product = context.require_app()
56
56
 
57
57
  click.secho(f"\n⚠️ This will completely wipe {product} ({env}):", fg="yellow")
58
- click.echo(" - Stop all Docker containers and DELETE ALL VOLUMES/DATA (irreversible)")
58
+ click.echo(
59
+ " - Stop all Docker containers and DELETE ALL VOLUMES/DATA (irreversible)"
60
+ )
59
61
  click.echo(" - Reset the database and regenerate migrations")
60
62
  click.echo(" - Clear uploads and application log")
61
63
  click.echo()
@@ -263,13 +263,7 @@ def make_product(name, spl_name, features_file, force):
263
263
  gid = 1000
264
264
  do_chown = sys.platform.startswith("linux")
265
265
  dir_mode = stat.S_IRWXU | stat.S_IRWXG | stat.S_IROTH | stat.S_IXOTH
266
- file_mode = (
267
- stat.S_IRUSR
268
- | stat.S_IWUSR
269
- | stat.S_IRGRP
270
- | stat.S_IWGRP
271
- | stat.S_IROTH
272
- )
266
+ file_mode = stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IWGRP | stat.S_IROTH
273
267
 
274
268
  def _maybe_chown(path):
275
269
  if not do_chown:
@@ -29,7 +29,7 @@ def _parse_env_line(line: str):
29
29
  return None
30
30
 
31
31
  if stripped.startswith("export ") or stripped.startswith("export\t"):
32
- stripped = stripped[len("export"):].lstrip()
32
+ stripped = stripped[len("export") :].lstrip()
33
33
 
34
34
  key, value = stripped.split("=", 1)
35
35
  key = key.strip()