splent-cli 1.28.2__tar.gz → 1.29.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.
- {splent_cli-1.28.2/src/splent_cli.egg-info → splent_cli-1.29.0}/PKG-INFO +1 -1
- {splent_cli-1.28.2 → splent_cli-1.29.0}/pyproject.toml +1 -1
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/product/product_build.py +42 -5
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/product/product_create.py +12 -1
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/product/product_deploy.py +45 -1
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/product/product_env.py +9 -2
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/product/product_release.py +83 -47
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/product/product_sync_template.py +11 -1
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/release/release_resume.py +16 -9
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/tokens_setup.py +4 -1
- splent_cli-1.29.0/src/splent_cli/services/image_registry.py +173 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/services/registry.py +100 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/services/release.py +10 -6
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/services/release_gate.py +107 -18
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/utils/git_url.py +21 -3
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/utils/template_drift.py +25 -1
- {splent_cli-1.28.2 → splent_cli-1.29.0/src/splent_cli.egg-info}/PKG-INFO +1 -1
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli.egg-info/SOURCES.txt +1 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/LICENSE +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/README.md +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/setup.cfg +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/__init__.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/__main__.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/cli.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/__init__.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/cache/__init__.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/cache/cache_clear.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/cache/cache_orphans.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/cache/cache_outdated.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/cache/cache_prune.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/cache/cache_size.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/cache/cache_status.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/cache/cache_usage.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/cache/cache_versions.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/check/__init__.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/check/check_contracts.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/check/check_deps.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/check/check_docker.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/check/check_env.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/check/check_features.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/check/check_github.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/check/check_infra.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/check/check_product.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/check/check_pypi.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/check/check_pyproject.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/check/check_releases.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/clear/__init__.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/clear/clear_build.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/clear/clear_log.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/clear/clear_uploads.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/command/__init__.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/command/command_create.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/coverage.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/database/db_console.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/database/db_dump.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/database/db_migrate.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/database/db_reset.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/database/db_restore.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/database/db_rollback.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/database/db_seed.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/database/db_status.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/database/db_upgrade.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/doctor.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/env/env_list.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/env/env_set.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/env/env_show.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/export/__init__.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/export/export_puml.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/feature/feature_add.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/feature/feature_attach.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/feature/feature_clean.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/feature/feature_clone.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/feature/feature_compat.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/feature/feature_compile.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/feature/feature_contract.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/feature/feature_create.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/feature/feature_delete.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/feature/feature_detach.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/feature/feature_discard.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/feature/feature_drift.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/feature/feature_env.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/feature/feature_fork.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/feature/feature_git.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/feature/feature_hook_add.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/feature/feature_hook_remove.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/feature/feature_hooks.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/feature/feature_impact.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/feature/feature_info.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/feature/feature_inject_config.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/feature/feature_install.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/feature/feature_list.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/feature/feature_order.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/feature/feature_outdated.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/feature/feature_pin.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/feature/feature_pip_install.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/feature/feature_pull.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/feature/feature_refine.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/feature/feature_release.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/feature/feature_remove.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/feature/feature_rename.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/feature/feature_search.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/feature/feature_status.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/feature/feature_sync_template.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/feature/feature_test.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/feature/feature_translate.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/feature/feature_unlock.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/feature/feature_upgrade.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/feature/feature_versions.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/feature/feature_xray.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/lint.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/locust.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/marketplace/login.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/marketplace/logout.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/marketplace/marketplace_auth_utils.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/marketplace/marketplace_index.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/marketplace/whoami.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/product/__init__.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/product/product_auto_require.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/product/product_clean.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/product/product_commands.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/product/product_config.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/product/product_configure.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/product/product_console.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/product/product_containers.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/product/product_derive.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/product/product_deselect.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/product/product_down.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/product/product_drift.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/product/product_list.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/product/product_logs.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/product/product_missing.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/product/product_port.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/product/product_resolve.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/product/product_restart.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/product/product_routes.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/product/product_run.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/product/product_select.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/product/product_shell.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/product/product_signals.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/product/product_test.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/product/product_up.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/product/product_validate.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/release/__init__.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/release/release_core.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/selenium.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/spl/__init__.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/spl/spl_add_constraints.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/spl/spl_add_feature.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/spl/spl_compare.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/spl/spl_configurations.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/spl/spl_create.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/spl/spl_deps.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/spl/spl_features.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/spl/spl_fetch.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/spl/spl_info.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/spl/spl_list.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/spl/spl_outdated.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/spl/spl_pin.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/spl/spl_publish.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/spl/spl_remove_feature.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/spl/spl_utils.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/uvl/uvl_utils.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/version.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/services/__init__.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/services/compose.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/services/context.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/services/credentials.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/services/index_refresh.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/services/marketplace.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/services/marketplace_api.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/services/marketplace_url.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/services/preflight.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/services/pypi_quota.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/services/release_dry_run.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/services/spl_store.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/utils/__init__.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/utils/archetype.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/utils/cache_utils.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/utils/command_loader.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/utils/contract_freshness.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/utils/db_client.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/utils/db_utils.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/utils/decorators.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/utils/dynamic_imports.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/utils/feature_installer.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/utils/feature_utils.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/utils/forge.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/utils/integrity.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/utils/io_utils.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/utils/lifecycle.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/utils/manifest.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/utils/path_utils.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/utils/proc.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/utils/redact.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/utils/refinement_facts.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/utils/toml_edit.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/utils/upgrade_plan.py +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli.egg-info/dependency_links.txt +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli.egg-info/entry_points.txt +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli.egg-info/requires.txt +0 -0
- {splent_cli-1.28.2 → splent_cli-1.29.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.
|
|
3
|
+
Version: 1.29.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
|
|
@@ -88,6 +88,16 @@ OPTIONAL_DEPLOY_SETTINGS: tuple[tuple[str, str, tuple[str, ...]], ...] = (
|
|
|
88
88
|
"trusted proxy. true forces it on every cookie, false never sets it.",
|
|
89
89
|
),
|
|
90
90
|
),
|
|
91
|
+
(
|
|
92
|
+
"SPLENT_IMAGE",
|
|
93
|
+
"git.splent.io/<org>/<product>:stable",
|
|
94
|
+
(
|
|
95
|
+
"Image the web service runs. Unset means the image built on this",
|
|
96
|
+
"host. Set it to the image a release publishes, tagged stable, to",
|
|
97
|
+
"run releases without building here. Every deploy pulls it, and the",
|
|
98
|
+
"autodeploy feature follows it.",
|
|
99
|
+
),
|
|
100
|
+
),
|
|
91
101
|
(
|
|
92
102
|
"MAX_CONTENT_LENGTH",
|
|
93
103
|
"64M",
|
|
@@ -551,9 +561,34 @@ def _apply_restart_policy(svc_def: dict) -> None:
|
|
|
551
561
|
svc_def["restart"] = RESTART_POLICY
|
|
552
562
|
|
|
553
563
|
|
|
564
|
+
def resolve_product_placeholders(value: str, product: str, *, prod: bool) -> str:
|
|
565
|
+
"""Resolve ``__PRODUCT__`` in a feature's value for this product.
|
|
566
|
+
|
|
567
|
+
``__PRODUCT___web`` is the product's web container, which is
|
|
568
|
+
``<product>_web`` in development and ``<product>_web_deploy`` in
|
|
569
|
+
production (the prod compose template names it). Every other
|
|
570
|
+
``__PRODUCT__`` is the product name. product:build and
|
|
571
|
+
product:env --merge --prod both write .env.deploy, so both go through
|
|
572
|
+
this: the merge used to replace the plain name only and point a feature
|
|
573
|
+
at the development container's name in production.
|
|
574
|
+
"""
|
|
575
|
+
if "__PRODUCT__" not in value:
|
|
576
|
+
return value
|
|
577
|
+
if prod:
|
|
578
|
+
value = value.replace("__PRODUCT___web", f"{product}_web_deploy")
|
|
579
|
+
return value.replace("__PRODUCT__", product)
|
|
580
|
+
|
|
581
|
+
|
|
582
|
+
def local_or_registry_image(product: str) -> str:
|
|
583
|
+
"""The web image of a deploy: ``SPLENT_IMAGE`` when set, else the local build."""
|
|
584
|
+
return "${SPLENT_IMAGE:-" + product + ":latest}"
|
|
585
|
+
|
|
586
|
+
|
|
554
587
|
def apply_production_policies(compose_data: dict, product: str) -> dict:
|
|
555
588
|
"""Give every deployed service a restart policy, and the web and database
|
|
556
|
-
services a healthcheck, unless the compose file already set one.
|
|
589
|
+
services a healthcheck, unless the compose file already set one. The web
|
|
590
|
+
image becomes ``${SPLENT_IMAGE:-<product>:latest}``, so a host can run the
|
|
591
|
+
image a release published instead of building its own.
|
|
557
592
|
|
|
558
593
|
Applied by product:build to the merged deploy compose, so every product
|
|
559
594
|
gets it on its next build, whatever its docker-compose.prod.yml says and
|
|
@@ -570,6 +605,11 @@ def apply_production_policies(compose_data: dict, product: str) -> dict:
|
|
|
570
605
|
)
|
|
571
606
|
if web_name and isinstance(services[web_name], dict):
|
|
572
607
|
services[web_name].setdefault("healthcheck", dict(WEB_HEALTHCHECK))
|
|
608
|
+
# The local build, unless .env.deploy names a registry image. Only the
|
|
609
|
+
# plain local name is rewritten: an image the product chose on purpose
|
|
610
|
+
# is left alone.
|
|
611
|
+
if services[web_name].get("image") == f"{product}:latest":
|
|
612
|
+
services[web_name]["image"] = local_or_registry_image(product)
|
|
573
613
|
|
|
574
614
|
db_name = next(
|
|
575
615
|
(n for n in (f"{product}_db_deploy", f"{product}_db") if n in services),
|
|
@@ -1109,10 +1149,7 @@ def product_build(no_image, skip_preflight):
|
|
|
1109
1149
|
# share the product network, so the prod service cannot simply take the
|
|
1110
1150
|
# dev name as an alias. The CLI owns both names, so it owns the mapping.
|
|
1111
1151
|
for k, v in env_result.items():
|
|
1112
|
-
|
|
1113
|
-
env_result[k] = v.replace(
|
|
1114
|
-
"__PRODUCT___web", f"{product}_web_deploy"
|
|
1115
|
-
).replace("__PRODUCT__", product)
|
|
1152
|
+
env_result[k] = resolve_product_placeholders(v, product, prod=True)
|
|
1116
1153
|
|
|
1117
1154
|
# Remove __FEATURE_HOST_DIR__ variables — not needed in prod
|
|
1118
1155
|
# (templates are baked into Docker images, no bind mounts)
|
|
@@ -13,7 +13,12 @@ from jinja2 import Environment, FileSystemLoader, select_autoescape
|
|
|
13
13
|
|
|
14
14
|
from splent_cli.utils.path_utils import PathUtils
|
|
15
15
|
from splent_cli.services import context, spl_store
|
|
16
|
-
from splent_cli.utils.template_drift import
|
|
16
|
+
from splent_cli.utils.template_drift import (
|
|
17
|
+
DEFAULT_UPGRADE_SCHEDULE,
|
|
18
|
+
is_reserved_repo_name,
|
|
19
|
+
not_a_product_reason,
|
|
20
|
+
)
|
|
21
|
+
from splent_cli.utils.template_drift import _forge_host as _template_forge_host
|
|
17
22
|
|
|
18
23
|
try:
|
|
19
24
|
from importlib.metadata import version as _pkg_version
|
|
@@ -218,6 +223,10 @@ def make_product(name, spl_name, spl_doi, features_file, force):
|
|
|
218
223
|
# Dropping it here made every product created this way fall back to
|
|
219
224
|
# "<name>.uvl" and 404, with nothing local left that knew the real name.
|
|
220
225
|
"spl_file": pin.file or "",
|
|
226
|
+
# The forge workflows. The same values product:sync-template --ci
|
|
227
|
+
# renders, so a new product does not start out drifted.
|
|
228
|
+
"forge_host": _template_forge_host(),
|
|
229
|
+
"upgrade_schedule": DEFAULT_UPGRADE_SCHEDULE,
|
|
221
230
|
# Production persistence. These switch on the named-volume mounts in
|
|
222
231
|
# the prod compose template so uploads survive redeploys. Products
|
|
223
232
|
# scaffolded before these variables existed render without them and
|
|
@@ -304,6 +313,8 @@ def _write_product(env, name, base_path, template_ctx):
|
|
|
304
313
|
"scripts/05_0_start_app_dev.sh": "product/product_05_0_start_app_dev.sh.j2",
|
|
305
314
|
"scripts/05_1_start_app_prod.sh": "product/product_05_1_start_app_prod.sh.j2",
|
|
306
315
|
".gitignore": "product/product_.gitignore.j2",
|
|
316
|
+
".forgejo/workflows/splent-validate.yml": "product/product_ci_validate.yml.j2",
|
|
317
|
+
".forgejo/workflows/splent-upgrade.yml": "product/product_ci_upgrade.yml.j2",
|
|
307
318
|
"LICENSE": "product/product_LICENSE.j2",
|
|
308
319
|
"package.json": "product/product_package.json.j2",
|
|
309
320
|
"pyproject.toml": "product/product_pyproject.toml.j2",
|
|
@@ -441,9 +441,18 @@ def product_deploy(down, ci):
|
|
|
441
441
|
)
|
|
442
442
|
continue
|
|
443
443
|
if ci:
|
|
444
|
-
|
|
444
|
+
# The environment first. Without it, whatever the interactive
|
|
445
|
+
# deploy would offer as a default is taken (a random string
|
|
446
|
+
# for a secret, the conventional database names), so a feature
|
|
447
|
+
# that ships a <SET> secret does not stop an unattended deploy.
|
|
448
|
+
# What only the operator knows still has to come from them.
|
|
449
|
+
env_value = os.getenv(key) or suggest_value(key, product)
|
|
445
450
|
if env_value:
|
|
446
451
|
env_vars[key] = env_value
|
|
452
|
+
if not os.getenv(key):
|
|
453
|
+
click.echo(
|
|
454
|
+
click.style(" secret ", dim=True) + f"{key} generated"
|
|
455
|
+
)
|
|
447
456
|
else:
|
|
448
457
|
missing_vars.append(key)
|
|
449
458
|
else:
|
|
@@ -624,6 +633,41 @@ def product_deploy(down, ci):
|
|
|
624
633
|
# container starts.
|
|
625
634
|
compose.ensure_network(compose.network_name(product))
|
|
626
635
|
|
|
636
|
+
# A registry image (SPLENT_IMAGE) is pulled first: Compose only pulls an
|
|
637
|
+
# image it does not have, so a host that already ran an older build of
|
|
638
|
+
# the same tag would otherwise redeploy that one.
|
|
639
|
+
image = (env_vars.get("SPLENT_IMAGE") or "").strip()
|
|
640
|
+
if "/" in image:
|
|
641
|
+
click.echo(click.style(" image ", dim=True) + f"pulling {image}")
|
|
642
|
+
pulled = subprocess.run(
|
|
643
|
+
[
|
|
644
|
+
"docker",
|
|
645
|
+
"compose",
|
|
646
|
+
"-p",
|
|
647
|
+
compose.deploy_project_name(product),
|
|
648
|
+
"-f",
|
|
649
|
+
compose_path,
|
|
650
|
+
"--env-file",
|
|
651
|
+
env_path,
|
|
652
|
+
"pull",
|
|
653
|
+
f"{product}_web_deploy",
|
|
654
|
+
],
|
|
655
|
+
capture_output=True,
|
|
656
|
+
text=True,
|
|
657
|
+
cwd=docker_dir,
|
|
658
|
+
env={**os.environ, **host_docker_dir_env(workspace, product)},
|
|
659
|
+
)
|
|
660
|
+
if pulled.returncode != 0:
|
|
661
|
+
click.secho(f" Could not pull {image}.", fg="red")
|
|
662
|
+
detail = (pulled.stderr or pulled.stdout or "").strip().splitlines()
|
|
663
|
+
for line in detail[-5:]:
|
|
664
|
+
click.echo(f" {line}")
|
|
665
|
+
click.echo(
|
|
666
|
+
" Check SPLENT_IMAGE in docker/.env.deploy, and docker login to "
|
|
667
|
+
"that registry when the image is private."
|
|
668
|
+
)
|
|
669
|
+
raise SystemExit(1)
|
|
670
|
+
|
|
627
671
|
click.echo(click.style(" deploying ", dim=True) + f"{product} (prod)...")
|
|
628
672
|
|
|
629
673
|
try:
|
|
@@ -368,11 +368,18 @@ def product_env(generate, merge, env_name, process_all):
|
|
|
368
368
|
# second product of the same line came up.
|
|
369
369
|
merged["SPLENT_NETWORK"] = compose.network_name(product)
|
|
370
370
|
|
|
371
|
-
# Replace __PRODUCT__ placeholder with the actual product name
|
|
371
|
+
# Replace __PRODUCT__ placeholder with the actual product name.
|
|
372
|
+
# product_build imports this module, so the helper is imported here.
|
|
373
|
+
from splent_cli.commands.product.product_build import (
|
|
374
|
+
resolve_product_placeholders,
|
|
375
|
+
)
|
|
376
|
+
|
|
372
377
|
product_replaced = []
|
|
373
378
|
for k, v in merged.items():
|
|
374
379
|
if "__PRODUCT__" in v:
|
|
375
|
-
merged[k] =
|
|
380
|
+
merged[k] = resolve_product_placeholders(
|
|
381
|
+
v, product, prod=env_name == "prod"
|
|
382
|
+
)
|
|
376
383
|
product_replaced.append(k)
|
|
377
384
|
|
|
378
385
|
if env_name == "prod":
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"""
|
|
2
|
-
product:release
|
|
2
|
+
product:release, a product release: version bump, tag, forge, PyPI and the image.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
import os
|
|
@@ -10,7 +10,7 @@ from splent_cli.commands.product.product_build import (
|
|
|
10
10
|
build_production_image,
|
|
11
11
|
production_dockerfile,
|
|
12
12
|
)
|
|
13
|
-
from splent_cli.services import context, release, release_gate
|
|
13
|
+
from splent_cli.services import context, image_registry, release, release_gate
|
|
14
14
|
from splent_cli.utils.proc import run, require_docker
|
|
15
15
|
|
|
16
16
|
|
|
@@ -51,19 +51,48 @@ def _guard_all_features_pinned(product_path: str):
|
|
|
51
51
|
raise SystemExit(1)
|
|
52
52
|
|
|
53
53
|
|
|
54
|
-
def
|
|
55
|
-
"""
|
|
54
|
+
def release_targets(product: str, version: str, product_path: str, org: str):
|
|
55
|
+
"""The registries this release pushes the image to, from the product's pyproject."""
|
|
56
|
+
try:
|
|
57
|
+
registries, mirrors = image_registry.declared_registries(
|
|
58
|
+
os.path.join(product_path, "pyproject.toml")
|
|
59
|
+
)
|
|
60
|
+
except image_registry.RegistryDeclarationError as e:
|
|
61
|
+
click.secho(f" error: {e}", fg="red")
|
|
62
|
+
raise SystemExit(1)
|
|
63
|
+
return image_registry.image_targets(product, version, org, registries, mirrors)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _login(target) -> bool:
|
|
67
|
+
user, secret = target.credentials()
|
|
68
|
+
if not user or not secret:
|
|
69
|
+
return False
|
|
70
|
+
command = ["docker", "login", "-u", user, "--password-stdin"]
|
|
71
|
+
if target.host:
|
|
72
|
+
command.insert(2, target.host)
|
|
73
|
+
try:
|
|
74
|
+
run(command, input=secret, capture=True)
|
|
75
|
+
except subprocess.CalledProcessError:
|
|
76
|
+
return False
|
|
77
|
+
return True
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def release_docker_image(product: str, version: str, docker_dir: str, targets):
|
|
81
|
+
"""Build the production image once and push it to every registry.
|
|
56
82
|
|
|
57
83
|
Public because release:resume has to be able to finish this channel too:
|
|
58
84
|
the image is pushed last, after the forge and PyPI are already
|
|
59
85
|
irreversible.
|
|
60
86
|
|
|
61
87
|
The image is the one product:build makes, docker/Dockerfile.<product>.prod
|
|
62
|
-
built with the workspace as context, so what
|
|
63
|
-
deploy runs.
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
88
|
+
built with the workspace as context, so what a registry serves is what a
|
|
89
|
+
deploy runs. build_production_image stages the SPL's UVL model first, so
|
|
90
|
+
the pushed image ships the model the product pins even from a clean clone
|
|
91
|
+
where product:build never ran.
|
|
92
|
+
|
|
93
|
+
Each registry gets the version tag and the ``stable`` channel tag (Docker
|
|
94
|
+
Hub also ``latest``). A required registry that refuses the login or the
|
|
95
|
+
push stops the release here; a mirror that does is reported and skipped.
|
|
67
96
|
"""
|
|
68
97
|
require_docker()
|
|
69
98
|
|
|
@@ -76,50 +105,51 @@ def release_docker_image(product: str, version: str, docker_dir: str):
|
|
|
76
105
|
)
|
|
77
106
|
raise SystemExit(1)
|
|
78
107
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
108
|
+
usable = []
|
|
109
|
+
for target in targets:
|
|
110
|
+
click.echo(f" docker logging into {target.label}...")
|
|
111
|
+
if _login(target):
|
|
112
|
+
usable.append(target)
|
|
113
|
+
continue
|
|
114
|
+
if target.mirror:
|
|
115
|
+
click.secho(
|
|
116
|
+
f" docker the {target.label} mirror is left out, its login failed "
|
|
117
|
+
f"or {' / '.join(target.credential_names())} are not set",
|
|
118
|
+
fg="yellow",
|
|
119
|
+
)
|
|
120
|
+
continue
|
|
121
|
+
user_env, secret_env = target.credential_names()
|
|
90
122
|
click.secho(
|
|
91
|
-
" error:
|
|
92
|
-
|
|
93
|
-
+ "\n Set them in your environment (e.g. export DOCKERHUB_USERNAME=... "
|
|
94
|
-
"DOCKERHUB_PASSWORD=...) before releasing.",
|
|
123
|
+
f" error: could not log into {target.label}. Check {user_env} and "
|
|
124
|
+
f"{secret_env}.",
|
|
95
125
|
fg="red",
|
|
96
126
|
)
|
|
97
127
|
raise SystemExit(1)
|
|
98
128
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
click.echo(" docker logging into Docker Hub...")
|
|
102
|
-
run(
|
|
103
|
-
["docker", "login", "-u", username, "--password-stdin"],
|
|
104
|
-
input=password,
|
|
105
|
-
capture=True,
|
|
106
|
-
)
|
|
107
|
-
|
|
129
|
+
refs = [ref for target in usable for ref in target.refs]
|
|
108
130
|
click.echo(" docker building image...")
|
|
109
131
|
try:
|
|
110
|
-
build_production_image(
|
|
111
|
-
product,
|
|
112
|
-
str(context.workspace()),
|
|
113
|
-
docker_dir,
|
|
114
|
-
[f"{image_name}:{version}", f"{image_name}:latest"],
|
|
115
|
-
)
|
|
132
|
+
build_production_image(product, str(context.workspace()), docker_dir, refs)
|
|
116
133
|
except subprocess.CalledProcessError:
|
|
117
134
|
click.secho(" error: Docker image build failed.", fg="red")
|
|
118
135
|
raise SystemExit(1)
|
|
119
136
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
137
|
+
for target in usable:
|
|
138
|
+
click.echo(f" docker pushing to {target.label}...")
|
|
139
|
+
try:
|
|
140
|
+
for ref in target.refs:
|
|
141
|
+
run(["docker", "push", ref])
|
|
142
|
+
except subprocess.CalledProcessError:
|
|
143
|
+
if target.mirror:
|
|
144
|
+
click.secho(
|
|
145
|
+
f" docker the push to the {target.label} mirror failed and is "
|
|
146
|
+
"left out",
|
|
147
|
+
fg="yellow",
|
|
148
|
+
)
|
|
149
|
+
continue
|
|
150
|
+
click.secho(f" error: the push to {target.label} failed.", fg="red")
|
|
151
|
+
raise SystemExit(1)
|
|
152
|
+
click.echo(f" docker {', '.join(target.refs)}")
|
|
123
153
|
|
|
124
154
|
click.echo(" docker push complete")
|
|
125
155
|
|
|
@@ -139,7 +169,7 @@ def _left_out_flags(channels) -> list[str]:
|
|
|
139
169
|
|
|
140
170
|
@click.command(
|
|
141
171
|
"product:release",
|
|
142
|
-
short_help="Release a product: version bump, tag, forge
|
|
172
|
+
short_help="Release a product: version bump, tag, forge, PyPI and image registries.",
|
|
143
173
|
)
|
|
144
174
|
@click.argument("version", required=False, default=None)
|
|
145
175
|
@click.option("--product", default=None, help="Override SPLENT_APP.")
|
|
@@ -210,7 +240,7 @@ def product_release(
|
|
|
210
240
|
raise SystemExit(1)
|
|
211
241
|
org, repo_name = parts
|
|
212
242
|
|
|
213
|
-
#
|
|
243
|
+
# The image is a third channel, and it is the one that publishes LAST, so
|
|
214
244
|
# it is the one most able to diverge. It goes through the gate with the
|
|
215
245
|
# others instead of being discovered at the end.
|
|
216
246
|
channels = release.resolve_channels(
|
|
@@ -250,7 +280,12 @@ def product_release(
|
|
|
250
280
|
|
|
251
281
|
def _docker_hook(_path, ver):
|
|
252
282
|
if release_gate.DOCKER in channels:
|
|
253
|
-
release_docker_image(
|
|
283
|
+
release_docker_image(
|
|
284
|
+
product,
|
|
285
|
+
ver,
|
|
286
|
+
docker_dir,
|
|
287
|
+
release_targets(product, ver, product_path, org),
|
|
288
|
+
)
|
|
254
289
|
|
|
255
290
|
release.run_release_pipeline(
|
|
256
291
|
product,
|
|
@@ -262,8 +297,9 @@ def product_release(
|
|
|
262
297
|
channels=channels,
|
|
263
298
|
resume_target=resume_target,
|
|
264
299
|
allow_unfinished=allow_unfinished,
|
|
265
|
-
|
|
266
|
-
|
|
300
|
+
image_targets=release_targets(product, version, product_path, org)
|
|
301
|
+
if release_gate.DOCKER in channels
|
|
302
|
+
else None,
|
|
267
303
|
post_pypi_hook=_docker_hook,
|
|
268
304
|
wait=wait,
|
|
269
305
|
)
|
{splent_cli-1.28.2 → splent_cli-1.29.0}/src/splent_cli/commands/product/product_sync_template.py
RENAMED
|
@@ -37,6 +37,12 @@ from splent_cli.utils.template_drift import (
|
|
|
37
37
|
is_flag=True,
|
|
38
38
|
help="Update only docker/ files.",
|
|
39
39
|
)
|
|
40
|
+
@click.option(
|
|
41
|
+
"--ci",
|
|
42
|
+
"only_ci",
|
|
43
|
+
is_flag=True,
|
|
44
|
+
help="Update only the forge workflows in .forgejo/workflows/.",
|
|
45
|
+
)
|
|
40
46
|
@click.option(
|
|
41
47
|
"--dry-run",
|
|
42
48
|
is_flag=True,
|
|
@@ -48,6 +54,7 @@ def product_sync_template(
|
|
|
48
54
|
only_scripts,
|
|
49
55
|
only_entrypoints,
|
|
50
56
|
only_docker,
|
|
57
|
+
only_ci,
|
|
51
58
|
dry_run,
|
|
52
59
|
yes,
|
|
53
60
|
):
|
|
@@ -60,6 +67,7 @@ def product_sync_template(
|
|
|
60
67
|
splent product:sync-template myapp
|
|
61
68
|
splent product:sync-template myapp --scripts
|
|
62
69
|
splent product:sync-template myapp --docker
|
|
70
|
+
splent product:sync-template myapp --ci
|
|
63
71
|
splent product:sync-template myapp --dry-run
|
|
64
72
|
splent product:sync-template myapp --yes
|
|
65
73
|
"""
|
|
@@ -72,7 +80,7 @@ def product_sync_template(
|
|
|
72
80
|
product_path = resolve_product_dir(workspace, product_name)
|
|
73
81
|
|
|
74
82
|
# Select which groups to process
|
|
75
|
-
filter_active = only_scripts or only_entrypoints or only_docker
|
|
83
|
+
filter_active = only_scripts or only_entrypoints or only_docker or only_ci
|
|
76
84
|
groups_to_run: dict[str, dict] = {}
|
|
77
85
|
if not filter_active or only_scripts:
|
|
78
86
|
groups_to_run["scripts"] = PRODUCT_GROUPS["scripts"]
|
|
@@ -80,6 +88,8 @@ def product_sync_template(
|
|
|
80
88
|
groups_to_run["entrypoints"] = PRODUCT_GROUPS["entrypoints"]
|
|
81
89
|
if not filter_active or only_docker:
|
|
82
90
|
groups_to_run["docker"] = PRODUCT_GROUPS["docker"]
|
|
91
|
+
if not filter_active or only_ci:
|
|
92
|
+
groups_to_run["ci"] = PRODUCT_GROUPS["ci"]
|
|
83
93
|
|
|
84
94
|
ctx = product_ctx(product_name)
|
|
85
95
|
|
|
@@ -350,7 +350,11 @@ def release_resume(target, assume_yes, no_pypi, no_forge, no_github, no_docker,
|
|
|
350
350
|
)
|
|
351
351
|
raise SystemExit(1)
|
|
352
352
|
|
|
353
|
-
|
|
353
|
+
image_targets = (
|
|
354
|
+
_image_targets(label, normalized, path, repo)
|
|
355
|
+
if release_gate.DOCKER in channels
|
|
356
|
+
else None
|
|
357
|
+
)
|
|
354
358
|
|
|
355
359
|
click.echo()
|
|
356
360
|
click.secho(f" Resuming {label} {tag}", bold=True)
|
|
@@ -377,7 +381,7 @@ def release_resume(target, assume_yes, no_pypi, no_forge, no_github, no_docker,
|
|
|
377
381
|
version=normalized,
|
|
378
382
|
channels=channels,
|
|
379
383
|
resume=True,
|
|
380
|
-
|
|
384
|
+
image_targets=image_targets,
|
|
381
385
|
)
|
|
382
386
|
release_gate.render(report)
|
|
383
387
|
|
|
@@ -526,7 +530,8 @@ def release_resume(target, assume_yes, no_pypi, no_forge, no_github, no_docker,
|
|
|
526
530
|
if make_release:
|
|
527
531
|
steps.append(f"create the release for {tag} on the forge")
|
|
528
532
|
if push_image:
|
|
529
|
-
|
|
533
|
+
refs = ", ".join(f"{t.repository}:{normalized}" for t in image_targets or [])
|
|
534
|
+
steps.append(f"build and push the Docker image {refs}")
|
|
530
535
|
if make_snapshot:
|
|
531
536
|
steps.append(f"create the local snapshot for {tag}")
|
|
532
537
|
|
|
@@ -670,7 +675,9 @@ def release_resume(target, assume_yes, no_pypi, no_forge, no_github, no_docker,
|
|
|
670
675
|
from splent_cli.commands.product.product_release import release_docker_image
|
|
671
676
|
|
|
672
677
|
product = label.split("/")[-1]
|
|
673
|
-
release_docker_image(
|
|
678
|
+
release_docker_image(
|
|
679
|
+
product, normalized, os.path.join(path, "docker"), image_targets
|
|
680
|
+
)
|
|
674
681
|
|
|
675
682
|
if make_snapshot:
|
|
676
683
|
from splent_cli.commands.feature.feature_release import (
|
|
@@ -750,11 +757,11 @@ def _declares_pypi(pyproject: str) -> bool:
|
|
|
750
757
|
return release_gate.PYPI in {release_gate.canonical_channel(c) for c in channels}
|
|
751
758
|
|
|
752
759
|
|
|
753
|
-
def
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
return
|
|
760
|
+
def _image_targets(label: str, version: str, path: str, repo: str):
|
|
761
|
+
"""The registries the product's image goes to, as product:release names them."""
|
|
762
|
+
from splent_cli.commands.product.product_release import release_targets
|
|
763
|
+
|
|
764
|
+
return release_targets(label.split("/")[-1], version, path, repo.split("/")[0])
|
|
758
765
|
|
|
759
766
|
|
|
760
767
|
cli_command = release_resume
|
|
@@ -43,7 +43,10 @@ def tokens():
|
|
|
43
43
|
click.echo(f" 1. Go to {forge.host()} → Settings → Applications")
|
|
44
44
|
click.echo(" → Access Tokens")
|
|
45
45
|
click.echo(" 2. Generate new token")
|
|
46
|
-
click.echo(
|
|
46
|
+
click.echo(
|
|
47
|
+
" 3. Enable scopes: write:repository, write:organization and "
|
|
48
|
+
"write:package (product images go to the forge registry)"
|
|
49
|
+
)
|
|
47
50
|
click.echo(" 4. Copy the token (shown only once)")
|
|
48
51
|
click.echo()
|
|
49
52
|
click.secho(" Add to your .env:", fg="bright_black")
|