wexample-wex-addon-dev-php 12.3.0__tar.gz → 12.4.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.
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/PKG-INFO +6 -6
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/README.md +3 -3
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/pyproject.toml +3 -3
- {wexample_wex_addon_dev_php-12.3.0/src/wexample_wex_addon_dev_php/file → wexample_wex_addon_dev_php-12.4.0/src/wexample_wex_addon_dev_php/deployment}/__init__.py +0 -0
- wexample_wex_addon_dev_php-12.4.0/src/wexample_wex_addon_dev_php/deployment/step/symfony_env_local_deployment_step.py +288 -0
- {wexample_wex_addon_dev_php-12.3.0/src/wexample_wex_addon_dev_php/services/composer → wexample_wex_addon_dev_php-12.4.0/src/wexample_wex_addon_dev_php/formatter}/__init__.py +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/php_addon_manager.py +7 -0
- wexample_wex_addon_dev_php-12.4.0/src/wexample_wex_addon_dev_php/resources/docker/Dockerfile.roave +31 -0
- {wexample_wex_addon_dev_php-12.3.0/src/wexample_wex_addon_dev_php/services/composer/commands → wexample_wex_addon_dev_php-12.4.0/src/wexample_wex_addon_dev_php/services}/__init__.py +0 -0
- {wexample_wex_addon_dev_php-12.3.0/src/wexample_wex_addon_dev_php/services/composer/commands/service → wexample_wex_addon_dev_php-12.4.0/src/wexample_wex_addon_dev_php/services/composer}/__init__.py +0 -0
- {wexample_wex_addon_dev_php-12.3.0/src/wexample_wex_addon_dev_php/services/laravel → wexample_wex_addon_dev_php-12.4.0/src/wexample_wex_addon_dev_php/services/composer/commands/service}/__init__.py +0 -0
- {wexample_wex_addon_dev_php-12.3.0/src/wexample_wex_addon_dev_php/services/laravel/commands/db → wexample_wex_addon_dev_php-12.4.0/src/wexample_wex_addon_dev_php/services/laravel}/__init__.py +0 -0
- {wexample_wex_addon_dev_php-12.3.0/src/wexample_wex_addon_dev_php/services/phpmyadmin → wexample_wex_addon_dev_php-12.4.0/src/wexample_wex_addon_dev_php/services/php/ai}/__init__.py +0 -0
- {wexample_wex_addon_dev_php-12.3.0/src/wexample_wex_addon_dev_php/services/phpmyadmin/commands → wexample_wex_addon_dev_php-12.4.0/src/wexample_wex_addon_dev_php/services/php/ai/shared}/__init__.py +0 -0
- {wexample_wex_addon_dev_php-12.3.0/src/wexample_wex_addon_dev_php/services/symfony → wexample_wex_addon_dev_php-12.4.0/src/wexample_wex_addon_dev_php/services/phpmyadmin/commands}/__init__.py +0 -0
- {wexample_wex_addon_dev_php-12.3.0/src/wexample_wex_addon_dev_php/services/symfony/ai → wexample_wex_addon_dev_php-12.4.0/src/wexample_wex_addon_dev_php/services/phpmyadmin/commands/runtime}/__init__.py +0 -0
- {wexample_wex_addon_dev_php-12.3.0/src/wexample_wex_addon_dev_php/services/wordpress → wexample_wex_addon_dev_php-12.4.0/src/wexample_wex_addon_dev_php/services/symfony/commands/service}/__init__.py +0 -0
- {wexample_wex_addon_dev_php-12.3.0/src/wexample_wex_addon_dev_php/workdir → wexample_wex_addon_dev_php-12.4.0/src/wexample_wex_addon_dev_php/services/symfony/commands/translations}/__init__.py +0 -0
- wexample_wex_addon_dev_php-12.4.0/src/wexample_wex_addon_dev_php/services/symfony/commands/translations/translate.py +89 -0
- wexample_wex_addon_dev_php-12.4.0/src/wexample_wex_addon_dev_php/services/symfony/docker/docker-compose.yml +24 -0
- wexample_wex_addon_dev_php-12.4.0/src/wexample_wex_addon_dev_php/services/symfony/samples/env/dev/docker/docker-compose.yml +8 -0
- wexample_wex_addon_dev_php-12.4.0/src/wexample_wex_addon_dev_php/services/symfony/samples/env/local/docker/docker-compose.yml +11 -0
- wexample_wex_addon_dev_php-12.4.0/src/wexample_wex_addon_dev_php/services/symfony/samples/env/prod/docker/docker-compose.yml +8 -0
- wexample_wex_addon_dev_php-12.3.0/tests/.gitkeep → wexample_wex_addon_dev_php-12.4.0/src/wexample_wex_addon_dev_php/services/wordpress/__init__.py +0 -0
- wexample_wex_addon_dev_php-12.4.0/src/wexample_wex_addon_dev_php/workdir/__init__.py +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/workdir/php_package_workdir.py +73 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/workdir/php_workdir.py +77 -10
- wexample_wex_addon_dev_php-12.4.0/tests/.gitkeep +0 -0
- wexample_wex_addon_dev_php-12.4.0/tests/workdir/__init__.py +0 -0
- wexample_wex_addon_dev_php-12.3.0/src/wexample_wex_addon_dev_php/resources/docker/Dockerfile.roave +0 -22
- wexample_wex_addon_dev_php-12.3.0/src/wexample_wex_addon_dev_php/services/symfony/docker/docker-compose.yml +0 -6
- wexample_wex_addon_dev_php-12.3.0/src/wexample_wex_addon_dev_php/services/symfony/samples/env/dev/docker/docker-compose.yml +0 -4
- wexample_wex_addon_dev_php-12.3.0/src/wexample_wex_addon_dev_php/services/symfony/samples/env/local/docker/docker-compose.yml +0 -8
- wexample_wex_addon_dev_php-12.3.0/src/wexample_wex_addon_dev_php/services/symfony/samples/env/prod/docker/docker-compose.yml +0 -4
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/__init__.py +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/__pycache__/__init__.py +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/config_value/__init__.py +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/config_value/php_package_readme_config_value.py +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/const/__init__.py +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/const/tags.py +0 -0
- {wexample_wex_addon_dev_php-12.3.0/src/wexample_wex_addon_dev_php/formatter → wexample_wex_addon_dev_php-12.4.0/src/wexample_wex_addon_dev_php/deployment/step}/__init__.py +0 -0
- {wexample_wex_addon_dev_php-12.3.0/src/wexample_wex_addon_dev_php/services → wexample_wex_addon_dev_php-12.4.0/src/wexample_wex_addon_dev_php/file}/__init__.py +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/file/php_composer_json_file.py +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/formatter/php_code_formatter.py +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/py.typed +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/resources/.wex.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/resources/design_rules/php_code.md +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/resources/writing_rules/php_code.md +0 -0
- {wexample_wex_addon_dev_php-12.3.0/src/wexample_wex_addon_dev_php/services/frankenphp → wexample_wex_addon_dev_php-12.4.0/src/wexample_wex_addon_dev_php/services/composer/commands}/__init__.py +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/composer/commands/service/install_local.py +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/composer/commands/service/refresh_lock.py +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/composer/docker/.wex.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/composer/docker/docker-compose.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/composer/service.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0/src/wexample_wex_addon_dev_php/services/laravel/commands → wexample_wex_addon_dev_php-12.4.0/src/wexample_wex_addon_dev_php/services/frankenphp}/__init__.py +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/frankenphp/docker/.wex.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/frankenphp/docker/docker-compose.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/frankenphp/samples/.wex.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/frankenphp/samples/caddy/.wex.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/frankenphp/samples/caddy/Caddyfile +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/frankenphp/samples/docker/.wex.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/frankenphp/samples/docker/docker-compose.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/frankenphp/samples/env/dev/docker/.wex.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/frankenphp/samples/env/dev/docker/docker-compose.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/frankenphp/samples/env/local/docker/.wex.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/frankenphp/samples/env/local/docker/docker-compose.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/frankenphp/samples/env/prod/docker/.wex.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/frankenphp/samples/env/prod/docker/docker-compose.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/frankenphp/samples/php/.wex.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/frankenphp/samples/php/web.ini +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/frankenphp/service.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/laravel/app_service.py +0 -0
- {wexample_wex_addon_dev_php-12.3.0/src/wexample_wex_addon_dev_php/services/laravel/commands/maintenance → wexample_wex_addon_dev_php-12.4.0/src/wexample_wex_addon_dev_php/services/laravel/commands}/__init__.py +0 -0
- {wexample_wex_addon_dev_php-12.3.0/src/wexample_wex_addon_dev_php/services/laravel/commands/service → wexample_wex_addon_dev_php-12.4.0/src/wexample_wex_addon_dev_php/services/laravel/commands/db}/__init__.py +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/laravel/commands/db/migrate.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0/src/wexample_wex_addon_dev_php/services/php → wexample_wex_addon_dev_php-12.4.0/src/wexample_wex_addon_dev_php/services/laravel/commands/maintenance}/__init__.py +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/laravel/commands/maintenance/disable.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/laravel/commands/maintenance/enable.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0/src/wexample_wex_addon_dev_php/services/php/ai → wexample_wex_addon_dev_php-12.4.0/src/wexample_wex_addon_dev_php/services/laravel/commands/service}/__init__.py +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/laravel/commands/service/install_local.py +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/laravel/commands/service/refresh_lock.py +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/laravel/docker/.wex.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/laravel/docker/docker-compose.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/laravel/samples/.wex.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/laravel/samples/docker/docker-compose.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/laravel/samples/env/dev/docker/docker-compose.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/laravel/samples/env/prod/docker/docker-compose.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/laravel/service.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0/src/wexample_wex_addon_dev_php/services/php/ai/shared → wexample_wex_addon_dev_php-12.4.0/src/wexample_wex_addon_dev_php/services/php}/__init__.py +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/php/ai/shared/context.j2 +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/php/ai/shared/php.j2 +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/php/docker/.wex.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/php/docker/docker-compose.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/php/samples/.wex.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/php/samples/caddy/.wex.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/php/samples/caddy/Caddyfile +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/php/samples/docker/.wex.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/php/samples/docker/docker-compose.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/php/samples/env/dev/docker/.wex.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/php/samples/env/dev/docker/docker-compose.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/php/samples/env/local/docker/.wex.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/php/samples/env/local/docker/docker-compose.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/php/samples/env/prod/docker/.wex.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/php/samples/env/prod/docker/docker-compose.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/php/samples/php/.wex.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/php/samples/php/web.ini +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/php/service.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0/src/wexample_wex_addon_dev_php/services/phpmyadmin/commands/runtime → wexample_wex_addon_dev_php-12.4.0/src/wexample_wex_addon_dev_php/services/phpmyadmin}/__init__.py +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/phpmyadmin/docker/.wex.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/phpmyadmin/docker/docker-compose.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/phpmyadmin/env/.wex.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/phpmyadmin/env/local/docker/docker-compose.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/phpmyadmin/service.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0/src/wexample_wex_addon_dev_php/services/symfony/ai/agents → wexample_wex_addon_dev_php-12.4.0/src/wexample_wex_addon_dev_php/services/symfony}/__init__.py +0 -0
- {wexample_wex_addon_dev_php-12.3.0/src/wexample_wex_addon_dev_php/services/symfony/ai/agents/editor → wexample_wex_addon_dev_php-12.4.0/src/wexample_wex_addon_dev_php/services/symfony/ai}/__init__.py +0 -0
- {wexample_wex_addon_dev_php-12.3.0/src/wexample_wex_addon_dev_php/services/symfony/ai/shared → wexample_wex_addon_dev_php-12.4.0/src/wexample_wex_addon_dev_php/services/symfony/ai/agents}/__init__.py +0 -0
- {wexample_wex_addon_dev_php-12.3.0/src/wexample_wex_addon_dev_php/services/symfony/commands → wexample_wex_addon_dev_php-12.4.0/src/wexample_wex_addon_dev_php/services/symfony/ai/agents/editor}/__init__.py +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/symfony/ai/agents/editor/agent.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/symfony/ai/agents/editor/context.j2 +0 -0
- {wexample_wex_addon_dev_php-12.3.0/src/wexample_wex_addon_dev_php/services/symfony/commands/service → wexample_wex_addon_dev_php-12.4.0/src/wexample_wex_addon_dev_php/services/symfony/ai/shared}/__init__.py +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/symfony/ai/shared/context.j2 +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/symfony/app_service.py +0 -0
- {wexample_wex_addon_dev_php-12.3.0/src/wexample_wex_addon_dev_php/services/symfony/knowledge → wexample_wex_addon_dev_php-12.4.0/src/wexample_wex_addon_dev_php/services/symfony/commands}/__init__.py +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/symfony/commands/service/deploy.py +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/symfony/commands/service/install_local.py +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/symfony/commands/service/watch.py +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/symfony/docker/.wex.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0/tests/workdir → wexample_wex_addon_dev_php-12.4.0/src/wexample_wex_addon_dev_php/services/symfony/knowledge}/__init__.py +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/symfony/knowledge/entity.md +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/symfony/samples/.wex.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/symfony/samples/docker/.wex.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/symfony/samples/docker/docker-compose.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/symfony/samples/docker/env.build +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/symfony/samples/docker/images/.wex.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/symfony/samples/docker/images/Dockerfile.dev +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/symfony/samples/docker/images/Dockerfile.release +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/symfony/samples/env/dev/docker/.wex.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/symfony/samples/env/local/docker/.wex.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/symfony/samples/env/prod/docker/.wex.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/symfony/service.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/wordpress/commands/__init__.py +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/wordpress/commands/service/__init__.py +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/wordpress/commands/url/__init__.py +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/wordpress/commands/url/replace.py +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/wordpress/docker/.wex.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/wordpress/docker/docker-compose.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/wordpress/samples/.wex.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/wordpress/samples/docker/docker-compose-cli.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/wordpress/samples/docker/docker-compose.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/wordpress/samples/env/dev/docker/docker-compose.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/wordpress/samples/env/local/wp-cli/.gitkeep +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/wordpress/samples/env/prod/docker/docker-compose.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/services/wordpress/service.yml +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/workdir/php_packages_suite_workdir.py +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/src/wexample_wex_addon_dev_php/workdir/php_symfony_workdir.py +0 -0
- {wexample_wex_addon_dev_php-12.3.0 → wexample_wex_addon_dev_php-12.4.0}/tests/workdir/test_php_package_workdir.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: wexample-wex-addon-dev-php
|
|
3
|
-
Version: 12.
|
|
3
|
+
Version: 12.4.0
|
|
4
4
|
Summary: Extends wex with PHP-specific development commands for Composer, Laravel, Symfony, and WordPress services running in Docker containers
|
|
5
5
|
Author-Email: weeger <contact@wexample.com>
|
|
6
6
|
License: MIT
|
|
@@ -13,8 +13,8 @@ Requires-Dist: attrs>=23.1.0
|
|
|
13
13
|
Requires-Dist: cattrs>=23.1.0
|
|
14
14
|
Requires-Dist: wexample-filestate-php>=6.4.0
|
|
15
15
|
Requires-Dist: wexample-filestate-symfony>=2.0.0
|
|
16
|
-
Requires-Dist: wexample-wex-addon-ai>=16.
|
|
17
|
-
Requires-Dist: wexample-wex-addon-app>=32.
|
|
16
|
+
Requires-Dist: wexample-wex-addon-ai>=16.1.0
|
|
17
|
+
Requires-Dist: wexample-wex-addon-app>=32.2.0
|
|
18
18
|
Requires-Dist: wexample-wex-addon-dev-javascript>=8.2.0
|
|
19
19
|
Provides-Extra: dev
|
|
20
20
|
Requires-Dist: pytest; extra == "dev"
|
|
@@ -23,7 +23,7 @@ Description-Content-Type: text/markdown
|
|
|
23
23
|
|
|
24
24
|
# wex_addon_dev_php
|
|
25
25
|
|
|
26
|
-
Version: 12.
|
|
26
|
+
Version: 12.4.0
|
|
27
27
|
|
|
28
28
|
`wex_addon_dev_php` extends the wex CLI with PHP-specific development commands for Composer, Laravel, Symfony, and WordPress services running in Docker containers. It is aimed at PHP developers who manage their apps through wex and need framework-aware automation — dependency wiring, migration runs, lock-file refreshes — executed directly inside the running service containers. The addon registers four workdir types (`php`, `php-package`, `php-packages-suite`, `php-symfony`) and contributes its commands through the standard `PhpAddonManager` plugin point.
|
|
29
29
|
|
|
@@ -275,8 +275,8 @@ Visit the [Wexample Suite documentation](https://docs.wexample.com) for the comp
|
|
|
275
275
|
- cattrs: >=23.1.0
|
|
276
276
|
- wexample-filestate-php: >=6.4.0
|
|
277
277
|
- wexample-filestate-symfony: >=2.0.0
|
|
278
|
-
- wexample-wex-addon-ai: >=16.
|
|
279
|
-
- wexample-wex-addon-app: >=32.
|
|
278
|
+
- wexample-wex-addon-ai: >=16.1.0
|
|
279
|
+
- wexample-wex-addon-app: >=32.2.0
|
|
280
280
|
- wexample-wex-addon-dev-javascript: >=8.2.0
|
|
281
281
|
|
|
282
282
|
## Versioning & Compatibility Policy
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# wex_addon_dev_php
|
|
2
2
|
|
|
3
|
-
Version: 12.
|
|
3
|
+
Version: 12.4.0
|
|
4
4
|
|
|
5
5
|
`wex_addon_dev_php` extends the wex CLI with PHP-specific development commands for Composer, Laravel, Symfony, and WordPress services running in Docker containers. It is aimed at PHP developers who manage their apps through wex and need framework-aware automation — dependency wiring, migration runs, lock-file refreshes — executed directly inside the running service containers. The addon registers four workdir types (`php`, `php-package`, `php-packages-suite`, `php-symfony`) and contributes its commands through the standard `PhpAddonManager` plugin point.
|
|
6
6
|
|
|
@@ -252,8 +252,8 @@ Visit the [Wexample Suite documentation](https://docs.wexample.com) for the comp
|
|
|
252
252
|
- cattrs: >=23.1.0
|
|
253
253
|
- wexample-filestate-php: >=6.4.0
|
|
254
254
|
- wexample-filestate-symfony: >=2.0.0
|
|
255
|
-
- wexample-wex-addon-ai: >=16.
|
|
256
|
-
- wexample-wex-addon-app: >=32.
|
|
255
|
+
- wexample-wex-addon-ai: >=16.1.0
|
|
256
|
+
- wexample-wex-addon-app: >=32.2.0
|
|
257
257
|
- wexample-wex-addon-dev-javascript: >=8.2.0
|
|
258
258
|
|
|
259
259
|
## Versioning & Compatibility Policy
|
|
@@ -6,7 +6,7 @@ build-backend = "pdm.backend"
|
|
|
6
6
|
|
|
7
7
|
[project]
|
|
8
8
|
name = "wexample-wex-addon-dev-php"
|
|
9
|
-
version = "12.
|
|
9
|
+
version = "12.4.0"
|
|
10
10
|
description = "Extends wex with PHP-specific development commands for Composer, Laravel, Symfony, and WordPress services running in Docker containers"
|
|
11
11
|
authors = [
|
|
12
12
|
{ name = "weeger", email = "contact@wexample.com" },
|
|
@@ -22,8 +22,8 @@ dependencies = [
|
|
|
22
22
|
"cattrs>=23.1.0",
|
|
23
23
|
"wexample-filestate-php>=6.4.0",
|
|
24
24
|
"wexample-filestate-symfony>=2.0.0",
|
|
25
|
-
"wexample-wex-addon-ai>=16.
|
|
26
|
-
"wexample-wex-addon-app>=32.
|
|
25
|
+
"wexample-wex-addon-ai>=16.1.0",
|
|
26
|
+
"wexample-wex-addon-app>=32.2.0",
|
|
27
27
|
"wexample-wex-addon-dev-javascript>=8.2.0",
|
|
28
28
|
]
|
|
29
29
|
|
|
File without changes
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING, Any, ClassVar
|
|
4
|
+
|
|
5
|
+
from wexample_wex_addon_app.const.deployment import (
|
|
6
|
+
DEPLOYMENT_STATUS_KO,
|
|
7
|
+
DEPLOYMENT_STATUS_OK,
|
|
8
|
+
DEPLOYMENT_STATUS_UNKNOWN,
|
|
9
|
+
)
|
|
10
|
+
from wexample_wex_addon_app.deployment.abstract_deployment_step import (
|
|
11
|
+
AbstractDeploymentStep,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from wexample_wex_addon_app.helper.remote import ResolvedRemote
|
|
16
|
+
from wexample_wex_addon_app.workdir.managed_workdir import ManagedWorkdir
|
|
17
|
+
|
|
18
|
+
# What a Symfony app's runtime always needs from the host, whatever `env.build` says:
|
|
19
|
+
# the build env reaches no service and holds no secret, by its own contract.
|
|
20
|
+
ALWAYS_FROM_THE_HOST: tuple[str, ...] = ("APP_SECRET", "DATABASE_URL")
|
|
21
|
+
|
|
22
|
+
# Config only these envs load: what it reads is never asked of a deployed host.
|
|
23
|
+
NOT_DEPLOYED_ENVS: tuple[str, ...] = ("dev", "test")
|
|
24
|
+
|
|
25
|
+
# A variable named so is a key the app signs with: made on the host, never asked.
|
|
26
|
+
SECRET_SUFFIX = "_SECRET"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _keys(content: str, names_only: bool = False) -> set[str]:
|
|
30
|
+
keys = set()
|
|
31
|
+
for line in content.splitlines():
|
|
32
|
+
line = line.strip()
|
|
33
|
+
if not line or line.startswith("#"):
|
|
34
|
+
continue
|
|
35
|
+
name = line if names_only else line.partition("=")[0]
|
|
36
|
+
name = name.removeprefix("export ").strip()
|
|
37
|
+
if name and (names_only or "=" in line):
|
|
38
|
+
keys.add(name)
|
|
39
|
+
return keys
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _quote(value: str) -> str:
|
|
43
|
+
"""A value as Symfony's Dotenv reads it back literally: single quotes take nothing
|
|
44
|
+
for a variable, and are only left for double ones when the value holds one."""
|
|
45
|
+
if "'" not in value:
|
|
46
|
+
return f"'{value}'"
|
|
47
|
+
escaped = value.replace("\\", "\\\\").replace('"', '\\"').replace("$", "\\$")
|
|
48
|
+
return f'"{escaped}"'
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _without_env_blocks(content: str) -> str:
|
|
52
|
+
"""The config with its `when@dev:` and `when@test:` blocks cut out."""
|
|
53
|
+
kept: list[str] = []
|
|
54
|
+
skipping = False
|
|
55
|
+
for line in content.splitlines():
|
|
56
|
+
if line and not line[0].isspace() and not line.startswith("#"):
|
|
57
|
+
skipping = line.rstrip().rstrip(":") in {
|
|
58
|
+
f"when@{env}" for env in NOT_DEPLOYED_ENVS
|
|
59
|
+
}
|
|
60
|
+
if not skipping:
|
|
61
|
+
kept.append(line)
|
|
62
|
+
return "\n".join(kept)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class SymfonyEnvLocalDeploymentStep(AbstractDeploymentStep):
|
|
66
|
+
"""The host's checkout has a `.env.local` giving every variable the app reads that the
|
|
67
|
+
image does not carry — the image's `.env` is `.wex/docker/env.build`, there to let the
|
|
68
|
+
kernel boot during the build and nothing more.
|
|
69
|
+
|
|
70
|
+
The variables are read off the app's own config (`%env(…)%`), so the list follows the
|
|
71
|
+
app; one read with a `default::` fallback, or only by `dev`/`test` config, is not
|
|
72
|
+
required. Only the names are looked at on the host, never the values.
|
|
73
|
+
|
|
74
|
+
Written when there is none, the way one copies a `.env.dist`: the signing secrets
|
|
75
|
+
generated, every other value the local `.env` gives, made the host's — the local
|
|
76
|
+
domain becomes the env's, and a secret the host generated for itself — a database
|
|
77
|
+
password — is named `${KEY}` and filled in on the host from its own env file, so it
|
|
78
|
+
never travels and nobody has to go and read it. Nothing is asked: what is copied as
|
|
79
|
+
it is gets named, for the operator to correct on the host if it must differ.
|
|
80
|
+
"""
|
|
81
|
+
|
|
82
|
+
LABEL: ClassVar[str] = "Symfony .env.local"
|
|
83
|
+
NAME: ClassVar[str] = "symfony_env_local"
|
|
84
|
+
PER_ENV: ClassVar[bool] = True
|
|
85
|
+
REQUIRES: ClassVar[tuple[str, ...]] = ("remote_app_dir",)
|
|
86
|
+
|
|
87
|
+
@staticmethod
|
|
88
|
+
def _build_env_keys(workdir: ManagedWorkdir) -> set[str]:
|
|
89
|
+
path = workdir.get_path() / ".wex" / "docker" / "env.build"
|
|
90
|
+
if not path.is_file():
|
|
91
|
+
return set()
|
|
92
|
+
return _keys(path.read_text(encoding="utf-8"))
|
|
93
|
+
|
|
94
|
+
@staticmethod
|
|
95
|
+
def _exists(remote: ResolvedRemote) -> bool:
|
|
96
|
+
import shlex
|
|
97
|
+
|
|
98
|
+
from wexample_wex_addon_app.helper.remote import remote_run
|
|
99
|
+
|
|
100
|
+
path = shlex.quote(f"{remote['path']}/.env.local")
|
|
101
|
+
return remote_run(remote, f"sudo -n test -f {path}").returncode == 0
|
|
102
|
+
|
|
103
|
+
@staticmethod
|
|
104
|
+
def _host_keys(remote: ResolvedRemote) -> set[str] | None:
|
|
105
|
+
"""The names the host's `.env.local` defines — values cut off on the host, so
|
|
106
|
+
none ever travels."""
|
|
107
|
+
import shlex
|
|
108
|
+
|
|
109
|
+
from wexample_wex_addon_app.helper.remote import remote_run
|
|
110
|
+
|
|
111
|
+
path = shlex.quote(f"{remote['path']}/.env.local")
|
|
112
|
+
result = remote_run(
|
|
113
|
+
remote,
|
|
114
|
+
f"sudo -n sh -c 'test -f {path} && cut -d= -f1 {path} || true'",
|
|
115
|
+
)
|
|
116
|
+
if result.returncode != 0:
|
|
117
|
+
return None
|
|
118
|
+
return _keys(result.stdout + "\n", names_only=True)
|
|
119
|
+
|
|
120
|
+
@staticmethod
|
|
121
|
+
def _local_values(workdir: ManagedWorkdir) -> dict[str, str]:
|
|
122
|
+
"""What the app's local `.env` gives — offered to the operator, never sent as is."""
|
|
123
|
+
path = workdir.get_path() / ".env"
|
|
124
|
+
if not path.is_file():
|
|
125
|
+
return {}
|
|
126
|
+
values = {}
|
|
127
|
+
for line in path.read_text(encoding="utf-8").splitlines():
|
|
128
|
+
line = line.strip()
|
|
129
|
+
if not line or line.startswith("#") or "=" not in line:
|
|
130
|
+
continue
|
|
131
|
+
key, _, value = line.removeprefix("export ").partition("=")
|
|
132
|
+
value = value.strip()
|
|
133
|
+
if len(value) >= 2 and value[0] == value[-1] and value[0] in "'\"":
|
|
134
|
+
value = value[1:-1]
|
|
135
|
+
values[key.strip()] = value
|
|
136
|
+
return values
|
|
137
|
+
|
|
138
|
+
def applies_to(self, workdir: ManagedWorkdir) -> bool:
|
|
139
|
+
from wexample_wex_addon_app.app_addon_manager import AppAddonManager
|
|
140
|
+
|
|
141
|
+
if self.kernel is None:
|
|
142
|
+
return False
|
|
143
|
+
services = AppAddonManager.from_kernel(self.kernel).get_app_services(workdir)
|
|
144
|
+
return any(service.name == "symfony" for service in services)
|
|
145
|
+
|
|
146
|
+
def apply(
|
|
147
|
+
self, workdir: ManagedWorkdir, remote: ResolvedRemote | None, io: Any = None
|
|
148
|
+
) -> str:
|
|
149
|
+
import secrets
|
|
150
|
+
import shlex
|
|
151
|
+
|
|
152
|
+
from wexample_wex_addon_app.helper.deployment import DEPLOYMENT_HOST_USER
|
|
153
|
+
from wexample_wex_addon_app.helper.remote import remote_run
|
|
154
|
+
|
|
155
|
+
defaults = self._host_defaults(workdir, remote)
|
|
156
|
+
values: dict[str, str] = {}
|
|
157
|
+
generated: list[str] = []
|
|
158
|
+
for key in self._needed(workdir):
|
|
159
|
+
if key.endswith(SECRET_SUFFIX):
|
|
160
|
+
values[key] = secrets.token_hex(32)
|
|
161
|
+
generated.append(key)
|
|
162
|
+
else:
|
|
163
|
+
# Written even empty: Symfony refuses a variable that is not there, and
|
|
164
|
+
# an empty one is how an app says « not used here ».
|
|
165
|
+
values[key] = defaults.get(key, "")
|
|
166
|
+
|
|
167
|
+
path = f"{remote['path']}/.env.local"
|
|
168
|
+
# Through stdin, never a command line: a secret must not show in the host's
|
|
169
|
+
# process list nor in a shell history. The `${KEY}` are resolved there.
|
|
170
|
+
result = remote_run(
|
|
171
|
+
remote,
|
|
172
|
+
f"sudo -n -u {DEPLOYMENT_HOST_USER} python3 -c {shlex.quote(_HOST_WRITER)} "
|
|
173
|
+
f"{shlex.quote(remote['path'] + '/.wex/local/env.yml')} {shlex.quote(path)}",
|
|
174
|
+
input="".join(f"{key}={_quote(value)}\n" for key, value in values.items()),
|
|
175
|
+
)
|
|
176
|
+
if result.returncode != 0:
|
|
177
|
+
raise RuntimeError(
|
|
178
|
+
f"Writing {path} on {remote['host']} failed: {result.stderr.strip()[:300]}"
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
made = f", generated {', '.join(generated)} (kept there, not shown)" if generated else ""
|
|
182
|
+
empty = [key for key, value in values.items() if not value]
|
|
183
|
+
copied = [
|
|
184
|
+
key for key, value in values.items()
|
|
185
|
+
if value and key not in generated and value == self._local_values(workdir).get(key)
|
|
186
|
+
]
|
|
187
|
+
rest = (f" Copied as they are locally: {', '.join(copied)}." if copied else "") + (
|
|
188
|
+
f" Left empty: {', '.join(empty)}." if empty else ""
|
|
189
|
+
)
|
|
190
|
+
return f"Wrote {path} on {remote['host']}{made}.{rest}"
|
|
191
|
+
|
|
192
|
+
def can_apply(self, workdir: ManagedWorkdir, remote: ResolvedRemote | None) -> bool:
|
|
193
|
+
# Written when there is none, never over one: an existing file is the host's.
|
|
194
|
+
return self._host_keys(remote) == set() and not self._exists(remote)
|
|
195
|
+
|
|
196
|
+
def check(self, workdir: ManagedWorkdir, remote: ResolvedRemote | None) -> tuple[str, str]:
|
|
197
|
+
present = self._host_keys(remote)
|
|
198
|
+
if present is None:
|
|
199
|
+
return DEPLOYMENT_STATUS_UNKNOWN, "could not read it"
|
|
200
|
+
if not present and not self._exists(remote):
|
|
201
|
+
return DEPLOYMENT_STATUS_KO, f"no {remote['path']}/.env.local"
|
|
202
|
+
missing = [key for key in self._needed(workdir) if key not in present]
|
|
203
|
+
if missing:
|
|
204
|
+
return DEPLOYMENT_STATUS_KO, f"no value for {', '.join(missing)}"
|
|
205
|
+
return DEPLOYMENT_STATUS_OK, f"{remote['path']}/.env.local"
|
|
206
|
+
|
|
207
|
+
def hint(self, workdir: ManagedWorkdir, remote: ResolvedRemote | None) -> str:
|
|
208
|
+
present = self._host_keys(remote) or set()
|
|
209
|
+
missing = [key for key in self._needed(workdir) if key not in present]
|
|
210
|
+
return (
|
|
211
|
+
f"Give {remote['path']}/.env.local on {remote['host']} (owned by www-data) the "
|
|
212
|
+
f"host's values for: {', '.join(missing)} — and mount it into the container, "
|
|
213
|
+
"the image only carries the build env."
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
def _host_defaults(
|
|
217
|
+
self, workdir: ManagedWorkdir, remote: ResolvedRemote
|
|
218
|
+
) -> dict[str, str]:
|
|
219
|
+
"""The local `.env` values, with what is this machine's replaced by the host's:
|
|
220
|
+
the domain, and every generated secret by a `${KEY}` the host resolves."""
|
|
221
|
+
import yaml
|
|
222
|
+
from wexample_wex_addon_app.helper.deployment import deployment_declared_vars
|
|
223
|
+
|
|
224
|
+
local_env = workdir.get_path() / ".wex" / "local" / "env.yml"
|
|
225
|
+
local_secrets = (
|
|
226
|
+
yaml.safe_load(local_env.read_text(encoding="utf-8")) or {}
|
|
227
|
+
if local_env.is_file()
|
|
228
|
+
else {}
|
|
229
|
+
)
|
|
230
|
+
replacements: dict[str, str] = {}
|
|
231
|
+
for key, meta in deployment_declared_vars(workdir, self.kernel).items():
|
|
232
|
+
value = local_secrets.get(key)
|
|
233
|
+
if isinstance(meta, dict) and meta.get("generated") and value:
|
|
234
|
+
replacements[str(value)] = "${" + key + "}"
|
|
235
|
+
domain = workdir.get_config().search("domain").get_str_or_none()
|
|
236
|
+
env_domain = (
|
|
237
|
+
workdir.get_config(env_name=remote["env"]).search("domain").get_str_or_none()
|
|
238
|
+
)
|
|
239
|
+
if domain and env_domain:
|
|
240
|
+
replacements[domain] = env_domain
|
|
241
|
+
|
|
242
|
+
defaults = {}
|
|
243
|
+
for key, value in self._local_values(workdir).items():
|
|
244
|
+
for old, new in replacements.items():
|
|
245
|
+
value = value.replace(old, new)
|
|
246
|
+
defaults[key] = value
|
|
247
|
+
return defaults
|
|
248
|
+
|
|
249
|
+
def _needed(self, workdir: ManagedWorkdir) -> list[str]:
|
|
250
|
+
"""The variables the app's config reads that the build env does not give, plus
|
|
251
|
+
those it never gives for real."""
|
|
252
|
+
import re
|
|
253
|
+
|
|
254
|
+
config = workdir.get_path() / "config"
|
|
255
|
+
referenced: set[str] = set()
|
|
256
|
+
for path in config.rglob("*.yaml"):
|
|
257
|
+
if any(part in NOT_DEPLOYED_ENVS for part in path.relative_to(config).parts):
|
|
258
|
+
continue
|
|
259
|
+
content = _without_env_blocks(path.read_text(encoding="utf-8"))
|
|
260
|
+
for match in re.finditer(r"%env\(([^)]+)\)%", content):
|
|
261
|
+
processors, _, key = match.group(1).rpartition(":")
|
|
262
|
+
# `default::KEY` falls back on its own: the app runs without it.
|
|
263
|
+
if "default:" not in f"{processors}:":
|
|
264
|
+
referenced.add(key)
|
|
265
|
+
built = self._build_env_keys(workdir)
|
|
266
|
+
needed = {key for key in referenced if key not in built} | set(ALWAYS_FROM_THE_HOST)
|
|
267
|
+
return sorted(needed)
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
# Run on the host: fills every `${KEY}` of the content on stdin from the host's env
|
|
271
|
+
# file, then writes it for the owner alone. A key the env file lacks stays as it is.
|
|
272
|
+
_HOST_WRITER = """
|
|
273
|
+
import os, re, sys
|
|
274
|
+
values = {}
|
|
275
|
+
with open(sys.argv[1]) as env:
|
|
276
|
+
for line in env:
|
|
277
|
+
match = re.match(r"^([A-Za-z_][A-Za-z0-9_]*):\\s*(.*?)\\s*$", line)
|
|
278
|
+
if match:
|
|
279
|
+
values[match[1]] = match[2].strip("\\"'")
|
|
280
|
+
content = re.sub(
|
|
281
|
+
r"\\$\\{([A-Za-z_][A-Za-z0-9_]*)\\}",
|
|
282
|
+
lambda m: values.get(m[1], m[0]),
|
|
283
|
+
sys.stdin.read(),
|
|
284
|
+
)
|
|
285
|
+
os.umask(0o077)
|
|
286
|
+
with open(sys.argv[2], "w") as target:
|
|
287
|
+
target.write(content)
|
|
288
|
+
"""
|
|
File without changes
|
|
@@ -20,6 +20,13 @@ class PhpAddonManager(FormatterContributingAddonMixin, AbstractAddonManager):
|
|
|
20
20
|
|
|
21
21
|
return wexample_wex_addon_dev_php
|
|
22
22
|
|
|
23
|
+
def get_deployment_step_classes(self) -> list[type]:
|
|
24
|
+
from wexample_wex_addon_dev_php.deployment.step.symfony_env_local_deployment_step import (
|
|
25
|
+
SymfonyEnvLocalDeploymentStep,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
return [SymfonyEnvLocalDeploymentStep]
|
|
29
|
+
|
|
23
30
|
def get_formatter_classes(self) -> list[type[AbstractFormatter]]:
|
|
24
31
|
from wexample_wex_addon_dev_php.formatter.php_code_formatter import (
|
|
25
32
|
PhpCodeFormatter,
|
wexample_wex_addon_dev_php-12.4.0/src/wexample_wex_addon_dev_php/resources/docker/Dockerfile.roave
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
FROM php:8.5-cli
|
|
2
|
+
|
|
3
|
+
RUN apt-get update && apt-get install -y \
|
|
4
|
+
git \
|
|
5
|
+
unzip \
|
|
6
|
+
libicu-dev \
|
|
7
|
+
libzip-dev \
|
|
8
|
+
libpng-dev \
|
|
9
|
+
&& rm -rf /var/lib/apt/lists/* \
|
|
10
|
+
&& docker-php-ext-install bcmath gd intl zip \
|
|
11
|
+
# A test suite compiling a Symfony container outgrows the CLI's 128M.
|
|
12
|
+
&& echo 'memory_limit=1G' > /usr/local/etc/php/conf.d/memory.ini
|
|
13
|
+
|
|
14
|
+
# The publish runs under sudo, so the container runs as root while the mounted
|
|
15
|
+
# repositories belong to the user: git refuses them as of dubious ownership,
|
|
16
|
+
# Roave fails, and every change in src/ reads as a breaking one.
|
|
17
|
+
RUN git config --system --add safe.directory '*'
|
|
18
|
+
|
|
19
|
+
RUN groupadd -g 1000 appuser && \
|
|
20
|
+
useradd -m -u 1000 -g 1000 -s /bin/bash appuser
|
|
21
|
+
|
|
22
|
+
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
|
|
23
|
+
|
|
24
|
+
USER appuser
|
|
25
|
+
RUN composer global require roave/backward-compatibility-check
|
|
26
|
+
|
|
27
|
+
ENV PATH="/home/appuser/.composer/vendor/bin:${PATH}"
|
|
28
|
+
|
|
29
|
+
WORKDIR /var/www/html
|
|
30
|
+
|
|
31
|
+
CMD ["tail", "-f", "/dev/null"]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
from wexample_cli.const.tags import AudienceTag, EffectTag, ScopeTag
|
|
6
|
+
from wexample_cli.decorator.command import command
|
|
7
|
+
from wexample_cli.decorator.option import option
|
|
8
|
+
from wexample_wex_core.const.globals import COMMAND_TYPE_SERVICE
|
|
9
|
+
|
|
10
|
+
from wexample_wex_addon_dev_php.const.tags import DomainTag
|
|
11
|
+
from wexample_wex_addon_dev_php.services.composer.commands.service.install_local import (
|
|
12
|
+
APP_DIR,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
if TYPE_CHECKING:
|
|
16
|
+
from wexample_app.response.abstract_response import AbstractResponse
|
|
17
|
+
from wexample_cli.context.execution_context import ExecutionContext
|
|
18
|
+
from wexample_wex_addon_app.service.app_service import AppService
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@option(
|
|
22
|
+
name="force",
|
|
23
|
+
type=bool,
|
|
24
|
+
default=False,
|
|
25
|
+
description="Translate again what an engine already translated; wording written by hand is kept",
|
|
26
|
+
)
|
|
27
|
+
@option(
|
|
28
|
+
name="locale",
|
|
29
|
+
type=str,
|
|
30
|
+
required=False,
|
|
31
|
+
default="",
|
|
32
|
+
description="Space-separated locales to translate into, enabled once done; every enabled locale but the default one if omitted",
|
|
33
|
+
)
|
|
34
|
+
@command(
|
|
35
|
+
type=COMMAND_TYPE_SERVICE,
|
|
36
|
+
description="Translate the interface and the content of a symfony app (wexample/symfony-translations)",
|
|
37
|
+
tags=[
|
|
38
|
+
DomainTag.LANGUAGE_PHP,
|
|
39
|
+
DomainTag.FRAMEWORK,
|
|
40
|
+
EffectTag.WRITE,
|
|
41
|
+
AudienceTag.AGENT_SAFE,
|
|
42
|
+
ScopeTag.APP,
|
|
43
|
+
ScopeTag.CONTAINER,
|
|
44
|
+
],
|
|
45
|
+
)
|
|
46
|
+
def symfony__translations__translate(
|
|
47
|
+
context: ExecutionContext,
|
|
48
|
+
service: AppService,
|
|
49
|
+
force: bool = False,
|
|
50
|
+
locale: str = "",
|
|
51
|
+
) -> AbstractResponse:
|
|
52
|
+
"""The locales are the app's own, read by Symfony from framework.enabled_locales
|
|
53
|
+
and default_locale: nothing to list here. Naming one is how a new locale is
|
|
54
|
+
added, `translate-files` enabling it once its files are written, so the next
|
|
55
|
+
run without any takes it along.
|
|
56
|
+
|
|
57
|
+
The interface first, as the content locales follow the interface ones. The
|
|
58
|
+
bundles are translated too: the app is where their wording is read.
|
|
59
|
+
|
|
60
|
+
Run in the terminal rather than captured: a run sends every text to the
|
|
61
|
+
engine and takes minutes, which a captured output would spend in silence.
|
|
62
|
+
"""
|
|
63
|
+
import sys
|
|
64
|
+
|
|
65
|
+
from wexample_app.response.interactive_shell_command_response import (
|
|
66
|
+
InteractiveShellCommandResponse,
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
container = service.addon_manager.get_service_docker_container_name(
|
|
70
|
+
service.name
|
|
71
|
+
)
|
|
72
|
+
if not container:
|
|
73
|
+
raise RuntimeError(f"No Docker container found for service '{service.name}'")
|
|
74
|
+
|
|
75
|
+
locales = " ".join(locale.split())
|
|
76
|
+
force_flag = " --force" if force else ""
|
|
77
|
+
script = (
|
|
78
|
+
f"cd {APP_DIR}"
|
|
79
|
+
f" && php bin/console translations:translate-files {locales} --include-bundles{force_flag}"
|
|
80
|
+
f" && php bin/console translations:translate-content{force_flag}"
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
# A terminal only when there is one: an agent runs this without.
|
|
84
|
+
tty = ["-ti"] if sys.stdin.isatty() else ["-i"]
|
|
85
|
+
|
|
86
|
+
return InteractiveShellCommandResponse(
|
|
87
|
+
kernel=context.kernel,
|
|
88
|
+
content=["docker", "exec", *tty, container, "/bin/sh", "-c", script],
|
|
89
|
+
)
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
services:
|
|
2
|
+
# What a host runs: the release image CI built, the code inside it and nothing
|
|
3
|
+
# mounted over it. APP_RELEASE_IMAGE is computed by `app::config/build` from the
|
|
4
|
+
# app's origin (or `docker.release_image`); BRANCH is the env's. The host's
|
|
5
|
+
# secrets reach it through the env composes (see samples/env/dev and prod).
|
|
6
|
+
symfony:
|
|
7
|
+
container_name: ${APP_PROJECT_NAME}_symfony
|
|
8
|
+
image: ${APP_RELEASE_IMAGE}:${BRANCH}
|
|
9
|
+
environment:
|
|
10
|
+
- VIRTUAL_HOST=${APP_DOMAINS_STRING}
|
|
11
|
+
- VIRTUAL_PORT=80
|
|
12
|
+
extends:
|
|
13
|
+
file: ${SERVICE_DEFAULT_COMPOSE}
|
|
14
|
+
service: default
|
|
15
|
+
|
|
16
|
+
# What a developer runs: the generic php image with the checkout mounted over
|
|
17
|
+
# /var/www/html, Caddyfile and php.ini bound from the app. Only the local env
|
|
18
|
+
# extends it (samples/env/local) — a service declared here starts nothing on its
|
|
19
|
+
# own, these files are only ever reached through `extends`.
|
|
20
|
+
symfony_local:
|
|
21
|
+
container_name: ${APP_PROJECT_NAME}_symfony
|
|
22
|
+
extends:
|
|
23
|
+
file: ${SERVICE_PHP_COMPOSE}
|
|
24
|
+
service: php
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
services:
|
|
2
|
+
# Local runs the image built from Dockerfile.dev with the checkout mounted —
|
|
3
|
+
# `symfony_local` — never the release image the base compose points at.
|
|
4
|
+
symfony:
|
|
5
|
+
extends:
|
|
6
|
+
file: ${SERVICE_SYMFONY_COMPOSE}
|
|
7
|
+
service: symfony_local
|
|
8
|
+
image: ${APP_NAME}:local
|
|
9
|
+
build:
|
|
10
|
+
context: ${APP_PATH}
|
|
11
|
+
dockerfile: .wex/docker/images/Dockerfile.dev
|
|
File without changes
|
|
File without changes
|