splent-cli 1.42.0__tar.gz → 1.44.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.42.0/src/splent_cli.egg-info → splent_cli-1.44.0}/PKG-INFO +1 -1
- {splent_cli-1.42.0 → splent_cli-1.44.0}/pyproject.toml +1 -1
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/cli.py +12 -3
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/check/check_env.py +2 -1
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/clear/clear_uploads.py +2 -2
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/database/db_reset.py +1 -1
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/database/db_rollback.py +1 -1
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/database/db_seed.py +3 -3
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/database/db_upgrade.py +1 -1
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/doctor.py +2 -1
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/feature/feature_compile.py +121 -51
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/feature/feature_release.py +159 -27
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/feature/feature_rename.py +2 -3
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/feature/feature_test.py +3 -3
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/product/product_commands.py +2 -4
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/product/product_create.py +15 -2
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/product/product_list.py +1 -2
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/product/product_release.py +1 -2
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/product/product_test.py +1 -1
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/uvl/uvl_utils.py +4 -11
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/version.py +1 -1
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/services/compose.py +10 -1
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/services/context.py +88 -13
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/services/release.py +9 -1
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/services/release_dry_run.py +70 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/services/spl_store.py +3 -2
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/feature/feature_MANIFEST.in.j2 +5 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/product/product_ci_validate.yml.j2 +22 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/utils/ci_services.py +24 -4
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/utils/ci_workflow.py +3 -1
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/utils/dynamic_imports.py +3 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/utils/feature_utils.py +58 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0/src/splent_cli.egg-info}/PKG-INFO +1 -1
- {splent_cli-1.42.0 → splent_cli-1.44.0}/COPYING +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/COPYING.LESSER +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/README.md +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/setup.cfg +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/__init__.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/__main__.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/__init__.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/cache/__init__.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/cache/cache_clear.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/cache/cache_orphans.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/cache/cache_outdated.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/cache/cache_prune.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/cache/cache_size.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/cache/cache_status.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/cache/cache_usage.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/cache/cache_versions.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/check/__init__.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/check/check_contracts.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/check/check_deps.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/check/check_docker.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/check/check_features.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/check/check_github.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/check/check_infra.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/check/check_product.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/check/check_pypi.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/check/check_pyproject.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/check/check_releases.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/check/check_vendor.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/clear/__init__.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/clear/clear_build.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/clear/clear_log.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/command/__init__.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/command/command_create.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/coverage.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/database/db_console.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/database/db_dump.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/database/db_migrate.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/database/db_restore.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/database/db_status.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/env/env_list.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/env/env_set.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/env/env_show.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/export/__init__.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/export/export_puml.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/feature/feature_add.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/feature/feature_attach.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/feature/feature_clean.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/feature/feature_clone.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/feature/feature_compat.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/feature/feature_contract.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/feature/feature_create.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/feature/feature_delete.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/feature/feature_detach.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/feature/feature_discard.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/feature/feature_drift.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/feature/feature_env.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/feature/feature_fork.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/feature/feature_git.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/feature/feature_hook_add.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/feature/feature_hook_remove.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/feature/feature_hooks.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/feature/feature_impact.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/feature/feature_info.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/feature/feature_inject_config.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/feature/feature_install.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/feature/feature_list.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/feature/feature_order.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/feature/feature_outdated.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/feature/feature_pin.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/feature/feature_pip_install.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/feature/feature_pull.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/feature/feature_refine.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/feature/feature_remove.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/feature/feature_search.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/feature/feature_status.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/feature/feature_sync_template.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/feature/feature_translate.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/feature/feature_unlock.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/feature/feature_upgrade.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/feature/feature_versions.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/feature/feature_xray.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/lint.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/locust.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/marketplace/login.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/marketplace/logout.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/marketplace/marketplace_auth_utils.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/marketplace/marketplace_index.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/marketplace/whoami.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/product/__init__.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/product/product_auto_require.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/product/product_build.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/product/product_clean.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/product/product_config.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/product/product_configure.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/product/product_console.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/product/product_containers.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/product/product_deploy.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/product/product_derive.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/product/product_deselect.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/product/product_down.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/product/product_drift.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/product/product_env.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/product/product_logs.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/product/product_missing.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/product/product_params.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/product/product_port.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/product/product_resolve.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/product/product_restart.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/product/product_routes.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/product/product_run.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/product/product_select.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/product/product_shell.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/product/product_signals.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/product/product_sync_template.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/product/product_up.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/product/product_validate.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/release/__init__.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/release/release_core.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/release/release_resume.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/selenium.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/spl/__init__.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/spl/spl_add_constraints.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/spl/spl_add_feature.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/spl/spl_compare.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/spl/spl_configurations.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/spl/spl_create.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/spl/spl_deps.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/spl/spl_features.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/spl/spl_fetch.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/spl/spl_info.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/spl/spl_list.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/spl/spl_outdated.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/spl/spl_pin.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/spl/spl_publish.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/spl/spl_remove_feature.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/spl/spl_utils.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/commands/tokens_setup.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/services/__init__.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/services/credentials.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/services/deploy_bundle.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/services/image_registry.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/services/index_refresh.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/services/marketplace.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/services/marketplace_api.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/services/marketplace_url.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/services/neutral_app.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/services/own_commands.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/services/preflight.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/services/pypi_quota.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/services/registry.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/services/release_gate.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/services/web_container.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/feature/feature_.gitignore.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/feature/feature_README.md.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/feature/feature_commands.py.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/feature/feature_config.py.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/feature/feature_docker-compose.dev.yml.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/feature/feature_docker-compose.prod.yml.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/feature/feature_docker.env.example.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/feature/feature_forms.py.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/feature/feature_hooks.py.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/feature/feature_init.py.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/feature/feature_init_config.py.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/feature/feature_init_light.py.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/feature/feature_init_service.py.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/feature/feature_migrations_alembic.ini.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/feature/feature_migrations_env.py.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/feature/feature_migrations_script.py.mako.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/feature/feature_models.py.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/feature/feature_pyproject.toml.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/feature/feature_pyproject_minimal.toml.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/feature/feature_repositories.py.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/feature/feature_routes.py.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/feature/feature_scripts.js.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/feature/feature_seeders.py.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/feature/feature_services.py.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/feature/feature_services_service.py.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/feature/feature_signals.py.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/feature/feature_templates_index.html.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/feature/feature_tests_conftest.py.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/feature/feature_tests_e2e.py.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/feature/feature_tests_functional.py.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/feature/feature_tests_integration.py.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/feature/feature_tests_locustfile.py.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/feature/feature_tests_unit.py.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/feature/feature_webpack.config.js.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/licenses/COPYING +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/licenses/COPYING.LESSER +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/product/product_.env.dev.example.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/product/product_.env.prod.example.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/product/product_.gitignore.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/product/product_00_core_requirements_dev.sh.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/product/product_00_install_features.sh.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/product/product_01_compile_assets.sh.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/product/product_02_0_db_wait_connection.sh.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/product/product_02_1_db_create_db_test.sh.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/product/product_02_2_db_create_splent_migrations.sh.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/product/product_03_initialize_migrations.sh.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/product/product_04_handle_migrations.sh.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/product/product_05_0_start_app_dev.sh.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/product/product_05_1_start_app_prod.sh.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/product/product_400.html +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/product/product_401.html +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/product/product_404.html +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/product/product_500.html +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/product/product_Dockerfile.dev.dockerignore.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/product/product_Dockerfile.dev.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/product/product_Dockerfile.prod.dockerignore.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/product/product_Dockerfile.prod.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/product/product_README.md.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/product/product_app.css +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/product/product_app.js +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/product/product_base_template.html +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/product/product_ci_upgrade.yml.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/product/product_config.py.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/product/product_docker-compose.dev.yml.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/product/product_docker-compose.prod.yml.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/product/product_dropzone.css +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/product/product_entrypoint.dev.sh.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/product/product_entrypoint.prod.sh.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/product/product_errors.py.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/product/product_favicon.svg +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/product/product_init.py.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/product/product_logging.py.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/product/product_own.css +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/product/product_package.json.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/product/product_pyproject.toml.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/templates/product/product_uvl.j2 +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/utils/__init__.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/utils/archetype.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/utils/cache_utils.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/utils/command_loader.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/utils/contract_freshness.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/utils/db_client.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/utils/db_utils.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/utils/decorators.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/utils/feature_installer.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/utils/feature_naming.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/utils/feature_params.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/utils/feature_requirements.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/utils/feature_resolution.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/utils/forge.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/utils/git_url.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/utils/integrity.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/utils/io_utils.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/utils/lifecycle.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/utils/manifest.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/utils/menu_keys.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/utils/migration_lock.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/utils/path_utils.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/utils/proc.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/utils/redact.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/utils/refinement_facts.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/utils/running_version.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/utils/template_drift.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/utils/toml_edit.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/utils/upgrade_plan.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli/utils/uvl_params.py +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli.egg-info/SOURCES.txt +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli.egg-info/dependency_links.txt +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli.egg-info/entry_points.txt +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli.egg-info/requires.txt +0 -0
- {splent_cli-1.42.0 → splent_cli-1.44.0}/src/splent_cli.egg-info/top_level.txt +0 -0
|
@@ -5,10 +5,13 @@ import os
|
|
|
5
5
|
import click
|
|
6
6
|
from dotenv import load_dotenv
|
|
7
7
|
|
|
8
|
+
from splent_cli.services import context
|
|
8
9
|
from splent_cli.utils.command_loader import load_commands
|
|
9
10
|
|
|
10
11
|
# From here on os.environ holds the workspace .env as well. What the shell
|
|
11
12
|
# itself exported is splent_cli.SHELL_ENV, taken before this line ran.
|
|
13
|
+
# Nothing exported is replaced, so a SPLENT_APP given to one command beats
|
|
14
|
+
# the selection in the file (context.active_app has the whole rule).
|
|
12
15
|
load_dotenv()
|
|
13
16
|
|
|
14
17
|
|
|
@@ -122,7 +125,7 @@ class SPLENTCLI(click.Group):
|
|
|
122
125
|
app = get_app()
|
|
123
126
|
with app.app_context():
|
|
124
127
|
self._own_cmds_cache = own_commands.collect(
|
|
125
|
-
|
|
128
|
+
context.active_app(), set(self.commands)
|
|
126
129
|
)
|
|
127
130
|
except Exception as e:
|
|
128
131
|
if debug:
|
|
@@ -170,7 +173,7 @@ class SPLENTCLI(click.Group):
|
|
|
170
173
|
"""
|
|
171
174
|
from splent_cli.services import web_container
|
|
172
175
|
|
|
173
|
-
product =
|
|
176
|
+
product = context.active_app()
|
|
174
177
|
if not product or web_container.is_product_container():
|
|
175
178
|
return
|
|
176
179
|
if not web_container.running(web_container.name(product)):
|
|
@@ -196,6 +199,12 @@ class SPLENTCLI(click.Group):
|
|
|
196
199
|
from splent_cli.utils.dynamic_imports import get_app
|
|
197
200
|
from splent_cli.utils.db_utils import check_db_connection
|
|
198
201
|
|
|
202
|
+
# For another product than the selection the CLI's container stays
|
|
203
|
+
# on the selection's network (compose.attach_self_to_network), so
|
|
204
|
+
# what reaches this product's services runs where they are.
|
|
205
|
+
if context.is_override():
|
|
206
|
+
self._delegate_to_the_product(ctx)
|
|
207
|
+
|
|
199
208
|
try:
|
|
200
209
|
app = get_app()
|
|
201
210
|
except Exception as exc:
|
|
@@ -205,7 +214,7 @@ class SPLENTCLI(click.Group):
|
|
|
205
214
|
# Only then: where the app builds here, the command runs here
|
|
206
215
|
# with the tools the CLI image has (ruff formats migrations).
|
|
207
216
|
self._delegate_to_the_product(ctx)
|
|
208
|
-
product =
|
|
217
|
+
product = context.active_app() or "The product"
|
|
209
218
|
raise click.ClickException(
|
|
210
219
|
f"{product}'s features need {missing}, which the product's "
|
|
211
220
|
"image installs and the CLI's does not.\n"
|
|
@@ -8,6 +8,7 @@ import sys
|
|
|
8
8
|
import click
|
|
9
9
|
import importlib.metadata
|
|
10
10
|
|
|
11
|
+
from splent_cli.services import context
|
|
11
12
|
from splent_cli.services.release_gate import pypi_credentials
|
|
12
13
|
from splent_cli.utils import forge
|
|
13
14
|
|
|
@@ -61,7 +62,7 @@ def check_env():
|
|
|
61
62
|
_warn(".env file not found in workspace")
|
|
62
63
|
|
|
63
64
|
# SPLENT_APP
|
|
64
|
-
app =
|
|
65
|
+
app = context.active_app(workspace)
|
|
65
66
|
if app:
|
|
66
67
|
app_path = os.path.join(workspace, app)
|
|
67
68
|
if os.path.isdir(app_path):
|
|
@@ -99,7 +99,7 @@ def resolve_uploads_dir(app=None) -> str:
|
|
|
99
99
|
product or its package, anything holding one of them, or a directory with
|
|
100
100
|
code at its top.
|
|
101
101
|
"""
|
|
102
|
-
product =
|
|
102
|
+
product = context.active_app() or ""
|
|
103
103
|
if not product or product in (".", "..") or os.sep in product or "/" in product:
|
|
104
104
|
raise UploadsDirError(f"'{product}' is not a valid product name.")
|
|
105
105
|
|
|
@@ -279,7 +279,7 @@ def clear_uploads(env_dev, env_prod, yes):
|
|
|
279
279
|
click.echo(click.style("Cannot specify both --dev and --prod.", fg="red"))
|
|
280
280
|
raise SystemExit(1)
|
|
281
281
|
env = context.resolve_env(env_dev, env_prod)
|
|
282
|
-
_run_where_the_uploads_are(
|
|
282
|
+
_run_where_the_uploads_are(context.active_app() or "", env, yes)
|
|
283
283
|
|
|
284
284
|
try:
|
|
285
285
|
uploads_dir = resolve_uploads_dir()
|
|
@@ -199,7 +199,7 @@ def db_reset(feature_name, yes):
|
|
|
199
199
|
"""
|
|
200
200
|
app = current_app
|
|
201
201
|
product_path = PathUtils.get_app_base_dir()
|
|
202
|
-
product_name =
|
|
202
|
+
product_name = context.active_app() or ""
|
|
203
203
|
|
|
204
204
|
if feature_name:
|
|
205
205
|
_reset_one_feature(app, feature_name, yes, product_path, product_name)
|
|
@@ -140,7 +140,7 @@ def _downgrade(directory: str, revision: str) -> None:
|
|
|
140
140
|
def db_rollback(feature, steps, to_base, cascade):
|
|
141
141
|
app = current_app
|
|
142
142
|
product_path = PathUtils.get_app_base_dir()
|
|
143
|
-
product_name =
|
|
143
|
+
product_name = context.active_app() or ""
|
|
144
144
|
|
|
145
145
|
if to_base:
|
|
146
146
|
source = click.get_current_context().get_parameter_source("steps")
|
|
@@ -23,7 +23,7 @@ def _resolve_feature_order(features_raw: list[str]) -> list[str]:
|
|
|
23
23
|
feature it refines (the refinement metadata the boot reads), with or
|
|
24
24
|
without a UVL. Features with neither keep their declared order.
|
|
25
25
|
"""
|
|
26
|
-
splent_app =
|
|
26
|
+
splent_app = context.active_app() or ""
|
|
27
27
|
working_dir = os.getenv("WORKING_DIR", "/workspace")
|
|
28
28
|
product_dir = os.path.join(working_dir, splent_app) if splent_app else ""
|
|
29
29
|
|
|
@@ -112,7 +112,7 @@ def _product_seeders(errors):
|
|
|
112
112
|
They are always loaded, also when a single module is seeded, because
|
|
113
113
|
their ``replaces`` decide which feature seeders may run at all.
|
|
114
114
|
"""
|
|
115
|
-
product =
|
|
115
|
+
product = context.active_app()
|
|
116
116
|
if not product:
|
|
117
117
|
return []
|
|
118
118
|
return _load_seeders(f"{product}.seeders", errors, label="product seeders")
|
|
@@ -154,7 +154,7 @@ def get_installed_seeders(specific_module=None):
|
|
|
154
154
|
)
|
|
155
155
|
|
|
156
156
|
targets = _module_names(specific_module) if specific_module else None
|
|
157
|
-
if targets and
|
|
157
|
+
if targets and context.active_app() in targets:
|
|
158
158
|
return product_seeders, errors
|
|
159
159
|
|
|
160
160
|
seeders = []
|
|
@@ -79,7 +79,7 @@ def _mark_without_migrations(
|
|
|
79
79
|
|
|
80
80
|
def _resolve_product():
|
|
81
81
|
"""Return (product_path, product_name) from env."""
|
|
82
|
-
product =
|
|
82
|
+
product = context.active_app() or ""
|
|
83
83
|
product_path = PathUtils.get_app_base_dir()
|
|
84
84
|
return product_path, product
|
|
85
85
|
|
|
@@ -19,6 +19,7 @@ from splent_cli.commands.check.check_product import check_product
|
|
|
19
19
|
from splent_cli.commands.feature.feature_status import feature_status
|
|
20
20
|
from splent_cli.commands.database.db_status import db_status
|
|
21
21
|
from splent_cli.commands.product.product_containers import product_docker
|
|
22
|
+
from splent_cli.services import context
|
|
22
23
|
|
|
23
24
|
|
|
24
25
|
SECTIONS = [
|
|
@@ -74,7 +75,7 @@ def _check_workspace_precondition():
|
|
|
74
75
|
elif not os.path.isdir(wd):
|
|
75
76
|
problems.append(f"WORKING_DIR points to a missing directory: {wd}")
|
|
76
77
|
|
|
77
|
-
app =
|
|
78
|
+
app = context.active_app(workspace)
|
|
78
79
|
if not app:
|
|
79
80
|
problems.append("SPLENT_APP is not set")
|
|
80
81
|
elif not os.path.isdir(os.path.join(workspace, app)):
|
|
@@ -123,6 +123,63 @@ def _container_workspace(container_id: str, workspace: str) -> tuple[str | None,
|
|
|
123
123
|
return None, mounted
|
|
124
124
|
|
|
125
125
|
|
|
126
|
+
def webpack_container(product: str, env: str, workspace: str) -> tuple[str | None, str]:
|
|
127
|
+
"""Where webpack runs for *product*: ``(container id, its workspace path)``.
|
|
128
|
+
|
|
129
|
+
The container is None inside the product's web container, where webpack
|
|
130
|
+
is at hand. Elsewhere (the CLI container, the host) it is the product's
|
|
131
|
+
running web container of *env*, and the path is where that container
|
|
132
|
+
sees *workspace*. Raises ClickException when there is none to run in.
|
|
133
|
+
feature:release --dry-run asks it too, to say whether the bundle can be
|
|
134
|
+
built.
|
|
135
|
+
"""
|
|
136
|
+
if _is_product_container():
|
|
137
|
+
return None, workspace
|
|
138
|
+
|
|
139
|
+
product_path = os.path.join(workspace, product)
|
|
140
|
+
docker_dir = os.path.join(product_path, "docker")
|
|
141
|
+
compose_file = compose.resolve_file(product_path, env)
|
|
142
|
+
|
|
143
|
+
if not compose_file:
|
|
144
|
+
raise click.ClickException(
|
|
145
|
+
f"No docker-compose file found for {product} ({env})"
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
project_name = compose.project_name(product, env)
|
|
149
|
+
container_id = compose.find_main_container(project_name, compose_file, docker_dir)
|
|
150
|
+
host = _on_host()
|
|
151
|
+
if not container_id and host:
|
|
152
|
+
container_id = _web_container_by_label(product, env)
|
|
153
|
+
|
|
154
|
+
if not container_id:
|
|
155
|
+
raise click.ClickException(
|
|
156
|
+
f"No running container found for {product} ({env}). "
|
|
157
|
+
f"Start it with splent product:up --{env}"
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
if not host:
|
|
161
|
+
return container_id, workspace
|
|
162
|
+
|
|
163
|
+
# webpack runs in the container, so it needs the container's paths, and
|
|
164
|
+
# only a container that mounts this workspace has the sources being
|
|
165
|
+
# compiled.
|
|
166
|
+
container_workspace, mounted = _container_workspace(container_id, workspace)
|
|
167
|
+
if container_workspace is None and mounted:
|
|
168
|
+
raise click.ClickException(
|
|
169
|
+
f"The {product} web container runs the workspace at "
|
|
170
|
+
f"{mounted}, not this one ({workspace}). Start this "
|
|
171
|
+
"workspace's product, or compile from the workspace that "
|
|
172
|
+
"runs it."
|
|
173
|
+
)
|
|
174
|
+
if container_workspace is None:
|
|
175
|
+
raise click.ClickException(
|
|
176
|
+
f"The {product} web container does not mount this "
|
|
177
|
+
f"workspace ({workspace}), so webpack cannot reach the "
|
|
178
|
+
"sources there."
|
|
179
|
+
)
|
|
180
|
+
return container_id, container_workspace
|
|
181
|
+
|
|
182
|
+
|
|
126
183
|
@click.command(
|
|
127
184
|
"feature:compile",
|
|
128
185
|
short_help="Compile frontend assets (webpack) for one or all features.",
|
|
@@ -131,66 +188,32 @@ def _container_workspace(container_id: str, workspace: str) -> tuple[str | None,
|
|
|
131
188
|
@click.option("--watch", is_flag=True, help="Enable watch mode for development.")
|
|
132
189
|
@click.option("--dev", "env_dev", is_flag=True, help="Use development environment.")
|
|
133
190
|
@click.option("--prod", "env_prod", is_flag=True, help="Use production environment.")
|
|
134
|
-
|
|
135
|
-
|
|
191
|
+
@click.option(
|
|
192
|
+
"--release",
|
|
193
|
+
"release_build",
|
|
194
|
+
is_flag=True,
|
|
195
|
+
help="Build the bundle a release ships: production mode, into an emptied "
|
|
196
|
+
"assets/dist, and fail when the feature has nothing to build. "
|
|
197
|
+
"feature:release runs it.",
|
|
198
|
+
)
|
|
199
|
+
def feature_compile(feature_name, watch, env_dev, env_prod, release_build):
|
|
200
|
+
if release_build and watch:
|
|
201
|
+
raise click.UsageError("--release builds the bundle once; drop --watch.")
|
|
202
|
+
production = (
|
|
203
|
+
os.getenv("FLASK_ENV", "develop") == "production" or env_prod or release_build
|
|
204
|
+
)
|
|
136
205
|
|
|
137
206
|
features = (
|
|
138
|
-
[
|
|
139
|
-
if feature_name
|
|
140
|
-
else get_features_from_pyproject()
|
|
207
|
+
[_feature_ref(feature_name)] if feature_name else get_features_from_pyproject()
|
|
141
208
|
)
|
|
142
209
|
|
|
143
210
|
env = context.resolve_env(env_dev, env_prod)
|
|
144
211
|
product = context.require_app()
|
|
145
212
|
workspace = str(context.workspace())
|
|
146
|
-
product_path = os.path.join(workspace, product)
|
|
147
213
|
|
|
148
214
|
# If running inside the product's web container, webpack is available locally.
|
|
149
215
|
# Otherwise (CLI container or host), delegate to the product container via docker exec.
|
|
150
|
-
container_workspace = workspace
|
|
151
|
-
if _is_product_container():
|
|
152
|
-
container_id = None
|
|
153
|
-
else:
|
|
154
|
-
docker_dir = os.path.join(product_path, "docker")
|
|
155
|
-
compose_file = compose.resolve_file(product_path, env)
|
|
156
|
-
|
|
157
|
-
if not compose_file:
|
|
158
|
-
raise click.ClickException(
|
|
159
|
-
f"No docker-compose file found for {product} ({env})"
|
|
160
|
-
)
|
|
161
|
-
|
|
162
|
-
project_name = compose.project_name(product, env)
|
|
163
|
-
container_id = compose.find_main_container(
|
|
164
|
-
project_name, compose_file, docker_dir
|
|
165
|
-
)
|
|
166
|
-
host = _on_host()
|
|
167
|
-
if not container_id and host:
|
|
168
|
-
container_id = _web_container_by_label(product, env)
|
|
169
|
-
|
|
170
|
-
if not container_id:
|
|
171
|
-
raise click.ClickException(
|
|
172
|
-
f"No running container found for {product} ({env}). "
|
|
173
|
-
f"Start it with splent product:up --{env}"
|
|
174
|
-
)
|
|
175
|
-
|
|
176
|
-
if host:
|
|
177
|
-
# webpack runs in the container, so it needs the container's
|
|
178
|
-
# paths, and only a container that mounts this workspace has the
|
|
179
|
-
# sources being compiled.
|
|
180
|
-
container_workspace, mounted = _container_workspace(container_id, workspace)
|
|
181
|
-
if container_workspace is None and mounted:
|
|
182
|
-
raise click.ClickException(
|
|
183
|
-
f"The {product} web container runs the workspace at "
|
|
184
|
-
f"{mounted}, not this one ({workspace}). Start this "
|
|
185
|
-
"workspace's product, or compile from the workspace that "
|
|
186
|
-
"runs it."
|
|
187
|
-
)
|
|
188
|
-
if container_workspace is None:
|
|
189
|
-
raise click.ClickException(
|
|
190
|
-
f"The {product} web container does not mount this "
|
|
191
|
-
f"workspace ({workspace}), so webpack cannot reach the "
|
|
192
|
-
"sources there."
|
|
193
|
-
)
|
|
216
|
+
container_id, container_workspace = webpack_container(product, env, workspace)
|
|
194
217
|
|
|
195
218
|
# Every feature is attempted, so one run reports every broken bundle, and
|
|
196
219
|
# the exit code then says whether any failed: the production Dockerfile
|
|
@@ -206,6 +229,7 @@ def feature_compile(feature_name, watch, env_dev, env_prod):
|
|
|
206
229
|
workspace,
|
|
207
230
|
product,
|
|
208
231
|
container_workspace=container_workspace,
|
|
232
|
+
release_build=release_build,
|
|
209
233
|
)
|
|
210
234
|
]
|
|
211
235
|
if failed and not watch:
|
|
@@ -217,6 +241,16 @@ def feature_compile(feature_name, watch, env_dev, env_prod):
|
|
|
217
241
|
raise SystemExit(1)
|
|
218
242
|
|
|
219
243
|
|
|
244
|
+
def _feature_ref(name: str) -> str:
|
|
245
|
+
"""*name* as typed, with the ``splent_feature_`` prefix on the feature's
|
|
246
|
+
own name: ``auth`` and ``splent_io/auth`` are ``splent_feature_auth``
|
|
247
|
+
and ``splent_io/splent_feature_auth``. feature:release passes the
|
|
248
|
+
namespaced ref, and prefixing the whole of it looked for
|
|
249
|
+
``splent_feature_splent_io/...`` and found no webpack config."""
|
|
250
|
+
namespace, sep, base = name.rpartition("/")
|
|
251
|
+
return f"{namespace}{sep}{get_normalize_feature_name_in_splent_format(base)}"
|
|
252
|
+
|
|
253
|
+
|
|
220
254
|
def _find_webpack(workspace, product, org_safe, base_name, version):
|
|
221
255
|
"""Locate webpack.config.js for an editable feature.
|
|
222
256
|
|
|
@@ -242,6 +276,7 @@ def _compile_in_container(
|
|
|
242
276
|
workspace,
|
|
243
277
|
product,
|
|
244
278
|
container_workspace=None,
|
|
279
|
+
release_build=False,
|
|
245
280
|
):
|
|
246
281
|
"""Compile one feature's assets. False only when webpack itself failed;
|
|
247
282
|
a skipped feature (pinned, or without webpack.config.js) is not a failure.
|
|
@@ -249,6 +284,12 @@ def _compile_in_container(
|
|
|
249
284
|
*container_workspace* is where the container that runs webpack sees the
|
|
250
285
|
workspace. It differs from *workspace* only when the command runs on the
|
|
251
286
|
host and delegates to the product's container.
|
|
287
|
+
|
|
288
|
+
*release_build* is feature:release's build (``--release``): webpack
|
|
289
|
+
empties assets/dist before it writes the bundle, so nothing a former
|
|
290
|
+
build left there ships with it, and a feature that would be skipped is a
|
|
291
|
+
failure, because the release would otherwise go on with whatever bundle
|
|
292
|
+
was there.
|
|
252
293
|
"""
|
|
253
294
|
parts = feature.split("/")
|
|
254
295
|
if len(parts) == 2:
|
|
@@ -263,6 +304,13 @@ def _compile_in_container(
|
|
|
263
304
|
# Pinned features are immutable — never compile them.
|
|
264
305
|
# Assets must be included at release time via feature:release.
|
|
265
306
|
if version:
|
|
307
|
+
if release_build:
|
|
308
|
+
click.secho(
|
|
309
|
+
f"❌ {feature} is pinned ({version}): a release builds the "
|
|
310
|
+
"bundle of the working copy at the workspace root.",
|
|
311
|
+
fg="red",
|
|
312
|
+
)
|
|
313
|
+
return False
|
|
266
314
|
click.echo(
|
|
267
315
|
click.style(
|
|
268
316
|
f" {feature} is pinned ({version}), skipping.",
|
|
@@ -274,6 +322,13 @@ def _compile_in_container(
|
|
|
274
322
|
webpack_file = _find_webpack(workspace, product, org_safe, base_name, version)
|
|
275
323
|
|
|
276
324
|
if not webpack_file:
|
|
325
|
+
if release_build:
|
|
326
|
+
click.secho(
|
|
327
|
+
f"❌ No webpack.config.js found in {feature} at the workspace "
|
|
328
|
+
"root, so there is no bundle to build.",
|
|
329
|
+
fg="red",
|
|
330
|
+
)
|
|
331
|
+
return False
|
|
277
332
|
click.echo(
|
|
278
333
|
click.style(
|
|
279
334
|
f"⚠ No webpack.config.js found in {feature}, skipping...", fg="yellow"
|
|
@@ -300,6 +355,8 @@ def _compile_in_container(
|
|
|
300
355
|
cmd_parts.append("--watch")
|
|
301
356
|
if not production:
|
|
302
357
|
cmd_parts.extend(["--devtool=source-map", "--no-cache"])
|
|
358
|
+
if release_build:
|
|
359
|
+
cmd_parts.append("--output-clean")
|
|
303
360
|
|
|
304
361
|
shell_cmd = " ".join(shlex.quote(p) for p in cmd_parts)
|
|
305
362
|
cd_cmd = f"cd {shlex.quote(product_root)} && {shell_cmd}"
|
|
@@ -308,7 +365,20 @@ def _compile_in_container(
|
|
|
308
365
|
# From the host: run via `docker exec` so webpack uses the container's
|
|
309
366
|
# node_modules.
|
|
310
367
|
if container_id:
|
|
311
|
-
|
|
368
|
+
# As the workspace's owner, as feature:test runs there: an exec runs
|
|
369
|
+
# as root in a development image, and a file webpack creates in
|
|
370
|
+
# assets/dist (a release's <bundle>.LICENSE.txt) stayed root's.
|
|
371
|
+
from splent_cli.commands.feature.feature_test import workspace_user
|
|
372
|
+
|
|
373
|
+
run_cmd = [
|
|
374
|
+
"docker",
|
|
375
|
+
"exec",
|
|
376
|
+
*workspace_user(container_id),
|
|
377
|
+
container_id,
|
|
378
|
+
"bash",
|
|
379
|
+
"-c",
|
|
380
|
+
cd_cmd,
|
|
381
|
+
]
|
|
312
382
|
tool_hint = (
|
|
313
383
|
"Install Docker Desktop or Docker Engine: "
|
|
314
384
|
"https://docs.docker.com/get-docker/"
|
|
@@ -1845,38 +1845,164 @@ def _commands_help_block(commands_help: dict) -> str:
|
|
|
1845
1845
|
return "".join(lines)
|
|
1846
1846
|
|
|
1847
1847
|
|
|
1848
|
-
# ──
|
|
1848
|
+
# ── Frontend bundle ───────────────────────────────────────────────────
|
|
1849
1849
|
|
|
1850
1850
|
|
|
1851
|
-
|
|
1852
|
-
|
|
1851
|
+
# How long the production build of one feature may take. A build cut short
|
|
1852
|
+
# stops the release, so the bound is generous: TinyMCE's takes seconds.
|
|
1853
|
+
_BUNDLE_TIMEOUT = 600
|
|
1853
1854
|
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
``
|
|
1857
|
-
|
|
1858
|
-
|
|
1855
|
+
|
|
1856
|
+
def _assets_dir(feature_path: str, namespace: str, feature_name: str) -> Path:
|
|
1857
|
+
"""``src/<org>/<feature>/assets``: the webpack config is in js/, and
|
|
1858
|
+
webpack writes the bundle to dist/."""
|
|
1859
|
+
return (
|
|
1860
|
+
Path(feature_path)
|
|
1861
|
+
/ "src"
|
|
1862
|
+
/ normalize_namespace(namespace)
|
|
1863
|
+
/ feature_name
|
|
1864
|
+
/ "assets"
|
|
1865
|
+
)
|
|
1866
|
+
|
|
1867
|
+
|
|
1868
|
+
def _bundle_files(feature_path: str, dist: Path) -> dict[str, str]:
|
|
1869
|
+
"""The sha256 of every file under *dist*, by path relative to the feature."""
|
|
1870
|
+
import hashlib
|
|
1871
|
+
|
|
1872
|
+
if not dist.is_dir():
|
|
1873
|
+
return {}
|
|
1874
|
+
return {
|
|
1875
|
+
path.relative_to(feature_path).as_posix(): hashlib.sha256(
|
|
1876
|
+
path.read_bytes()
|
|
1877
|
+
).hexdigest()
|
|
1878
|
+
for path in sorted(dist.rglob("*"))
|
|
1879
|
+
if path.is_file()
|
|
1880
|
+
}
|
|
1881
|
+
|
|
1882
|
+
|
|
1883
|
+
def _refuse_bundle(feature_ref: str, reason: str, output: str = "") -> None:
|
|
1884
|
+
click.secho(
|
|
1885
|
+
f" error: the frontend bundle of {feature_ref} was not built: {reason}.",
|
|
1886
|
+
fg="red",
|
|
1887
|
+
)
|
|
1888
|
+
lines = [line for line in output.splitlines() if line.strip()][-8:]
|
|
1889
|
+
for line in lines:
|
|
1890
|
+
click.secho(f" {line}", fg="bright_black")
|
|
1891
|
+
click.echo(
|
|
1892
|
+
" The release tags the bundle with the code, so it does not go on "
|
|
1893
|
+
"without one.\n"
|
|
1894
|
+
" webpack runs in the product's web container (splent product:up "
|
|
1895
|
+
"--dev starts it).\n"
|
|
1896
|
+
f" Try the build on its own with: splent feature:compile {feature_ref} "
|
|
1897
|
+
"--release\n"
|
|
1898
|
+
" No version bump, no commit, no tag, no release."
|
|
1899
|
+
)
|
|
1900
|
+
raise SystemExit(1)
|
|
1901
|
+
|
|
1902
|
+
|
|
1903
|
+
def _build_bundle(feature_path: str, namespace: str, feature_name: str):
|
|
1904
|
+
"""Build the frontend bundle the release ships, or stop the release.
|
|
1905
|
+
|
|
1906
|
+
None for a feature without ``assets/js/webpack.config.js``, which has no
|
|
1907
|
+
bundle. Otherwise the sha256 of every file the build left in
|
|
1908
|
+
``assets/dist``, by path relative to the feature, for
|
|
1909
|
+
:func:`_stage_bundle`.
|
|
1910
|
+
|
|
1911
|
+
Every channel installs what the tag holds: the snapshot in .splent_cache
|
|
1912
|
+
is a clone of it, pip builds a git+ install from it, and the wheel is
|
|
1913
|
+
built from the same tree. assets/dist is gitignored, so the tags of 13
|
|
1914
|
+
of uvlhub's 14 webpack features carried no bundle. Development served it
|
|
1915
|
+
from the working copy at the workspace root, and the forge CI and an
|
|
1916
|
+
image that installed from a tag answered 404. The release builds the
|
|
1917
|
+
bundle in production mode, into an emptied assets/dist, before the
|
|
1918
|
+
tests, and its commit carries it, so the tag, the wheel and the sdist
|
|
1919
|
+
hold the same bytes (SD-01: what is verified is what is deployed).
|
|
1920
|
+
|
|
1921
|
+
A build that cannot run, fails, or writes no bundle stops the release
|
|
1922
|
+
before anything versioned changes. It used to go on, and the package
|
|
1923
|
+
then shipped whatever bundle the working tree had, stale or none.
|
|
1859
1924
|
"""
|
|
1860
|
-
|
|
1925
|
+
assets = _assets_dir(feature_path, namespace, feature_name)
|
|
1926
|
+
if not (assets / "js" / "webpack.config.js").is_file():
|
|
1927
|
+
return None
|
|
1928
|
+
feature_ref = f"{namespace}/{feature_name}"
|
|
1929
|
+
click.echo(" bundle building assets/dist in production mode...")
|
|
1930
|
+
# This same CLI (sys.executable -m splent_cli), not whatever splent is
|
|
1931
|
+
# first on PATH, and webpack runs in the product's web container, found
|
|
1932
|
+
# from the host too.
|
|
1861
1933
|
try:
|
|
1862
1934
|
result = subprocess.run(
|
|
1863
|
-
[
|
|
1935
|
+
[
|
|
1936
|
+
sys.executable,
|
|
1937
|
+
"-m",
|
|
1938
|
+
"splent_cli",
|
|
1939
|
+
"feature:compile",
|
|
1940
|
+
feature_ref,
|
|
1941
|
+
"--release",
|
|
1942
|
+
],
|
|
1864
1943
|
capture_output=True,
|
|
1865
1944
|
text=True,
|
|
1866
|
-
timeout=
|
|
1945
|
+
timeout=_BUNDLE_TIMEOUT,
|
|
1867
1946
|
)
|
|
1868
1947
|
except subprocess.TimeoutExpired:
|
|
1869
|
-
|
|
1870
|
-
|
|
1948
|
+
_refuse_bundle(
|
|
1949
|
+
feature_ref, f"webpack did not finish within {_BUNDLE_TIMEOUT} seconds"
|
|
1950
|
+
)
|
|
1871
1951
|
except OSError as e:
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1952
|
+
_refuse_bundle(feature_ref, f"the CLI could not run ({e})")
|
|
1953
|
+
if result.returncode != 0:
|
|
1954
|
+
output = "\n".join(part for part in (result.stdout, result.stderr) if part)
|
|
1955
|
+
_refuse_bundle(feature_ref, "feature:compile --release failed", output)
|
|
1956
|
+
|
|
1957
|
+
built = _bundle_files(feature_path, assets / "dist")
|
|
1958
|
+
if not any(path.endswith(".js") for path in built):
|
|
1959
|
+
_refuse_bundle(feature_ref, "webpack wrote no bundle to assets/dist")
|
|
1960
|
+
click.echo(f" bundle built, {len(built)} file(s) in assets/dist")
|
|
1961
|
+
return built
|
|
1962
|
+
|
|
1963
|
+
|
|
1964
|
+
def _stage_bundle(feature_path: str, namespace: str, feature_name: str, built) -> None:
|
|
1965
|
+
"""Put the bundle :func:`_build_bundle` built into the release commit.
|
|
1966
|
+
|
|
1967
|
+
assets/dist is gitignored, and the release commit stages what git tracks
|
|
1968
|
+
and the new files it does not ignore, so the bundle is added here by
|
|
1969
|
+
name (``git add -f``). A file the build no longer writes, a bundle
|
|
1970
|
+
renamed or a source map dropped, is a tracked file gone, which the
|
|
1971
|
+
commit stages as a deletion.
|
|
1972
|
+
|
|
1973
|
+
The commit has to carry the bundle the build wrote. Anything that
|
|
1974
|
+
rewrote assets/dist since (a watch build of the same working copy)
|
|
1975
|
+
would tag another one, and that stops the release here.
|
|
1976
|
+
"""
|
|
1977
|
+
dist = _assets_dir(feature_path, namespace, feature_name) / "dist"
|
|
1978
|
+
if _bundle_files(feature_path, dist) != built:
|
|
1979
|
+
click.secho(
|
|
1980
|
+
" error: assets/dist changed after the release built it, so the "
|
|
1981
|
+
"release commit would carry another bundle.",
|
|
1982
|
+
fg="red",
|
|
1983
|
+
)
|
|
1984
|
+
click.echo(
|
|
1985
|
+
" Stop whatever rebuilds it (feature:compile --watch) and release "
|
|
1986
|
+
"again.\n"
|
|
1987
|
+
" The version was bumped but not committed."
|
|
1988
|
+
)
|
|
1989
|
+
raise SystemExit(1)
|
|
1990
|
+
try:
|
|
1991
|
+
subprocess.run(
|
|
1992
|
+
["git", "add", "-f", "--", *built],
|
|
1993
|
+
cwd=feature_path,
|
|
1994
|
+
check=True,
|
|
1995
|
+
capture_output=True,
|
|
1996
|
+
text=True,
|
|
1997
|
+
)
|
|
1998
|
+
except subprocess.CalledProcessError as e:
|
|
1999
|
+
click.secho(
|
|
2000
|
+
f" error: git could not stage the bundle: {(e.stderr or '').strip() or e}",
|
|
2001
|
+
fg="red",
|
|
2002
|
+
)
|
|
2003
|
+
click.echo(" The version was bumped but not committed.")
|
|
2004
|
+
raise SystemExit(1)
|
|
2005
|
+
click.echo(" bundle assets/dist goes into the release commit")
|
|
1880
2006
|
|
|
1881
2007
|
|
|
1882
2008
|
# ── Versioned snapshot ────────────────────────────────────────────────
|
|
@@ -2183,17 +2309,22 @@ def feature_release(
|
|
|
2183
2309
|
else "this package does not publish to the forge"
|
|
2184
2310
|
)
|
|
2185
2311
|
|
|
2312
|
+
# The bundle the release ships, by path: built before the tests, so they
|
|
2313
|
+
# run against it, and staged into the release commit, so the tag, the
|
|
2314
|
+
# wheel and the sdist all carry it.
|
|
2315
|
+
bundle: dict = {}
|
|
2316
|
+
|
|
2317
|
+
def _build(path, ver):
|
|
2318
|
+
bundle["files"] = _build_bundle(path, namespace, feature_name)
|
|
2319
|
+
|
|
2186
2320
|
def _pre_commit(path, ver):
|
|
2187
2321
|
click.echo(" contract updating from source code...")
|
|
2188
2322
|
from splent_cli.commands.feature.feature_contract import update_contract
|
|
2189
2323
|
|
|
2190
2324
|
update_contract(path, namespace, feature_name)
|
|
2191
2325
|
click.echo(" contract written to pyproject.toml")
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
# feature that tracks its bundles in git (auth does) commits the
|
|
2195
|
-
# bundle just built, the same one the wheel ships.
|
|
2196
|
-
_compile_before_release(feature_name)
|
|
2326
|
+
if bundle.get("files") is not None:
|
|
2327
|
+
_stage_bundle(path, namespace, feature_name, bundle["files"])
|
|
2197
2328
|
|
|
2198
2329
|
def _post_pypi(path, ver):
|
|
2199
2330
|
if release_gate.FORGE in channels:
|
|
@@ -2221,6 +2352,7 @@ def feature_release(
|
|
|
2221
2352
|
channels=channels,
|
|
2222
2353
|
resume_target=feature_name,
|
|
2223
2354
|
allow_unfinished=allow_unfinished,
|
|
2355
|
+
build_hook=_build,
|
|
2224
2356
|
pre_commit_hook=_pre_commit,
|
|
2225
2357
|
post_pypi_hook=_post_pypi,
|
|
2226
2358
|
wait=wait,
|
|
@@ -2440,7 +2572,7 @@ def _dry_run(
|
|
|
2440
2572
|
|
|
2441
2573
|
tag = f"v{version.lstrip('v')}"
|
|
2442
2574
|
git_state = release_dry_run.read_git_state(feature_path, tag)
|
|
2443
|
-
product =
|
|
2575
|
+
product = context.active_app()
|
|
2444
2576
|
|
|
2445
2577
|
rehearsal = release_dry_run.rehearse_feature_release(
|
|
2446
2578
|
feature_path=feature_path,
|