├── .cs ├── .php_cs.php ├── cs_ruleset.xml └── md_ruleset.xml ├── .github ├── FUNDING.yml ├── PULL_REQUEST_TEMPLATE.md ├── issue_template.md └── workflows │ ├── main-ci.yaml │ └── release.yaml ├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── Makefile ├── README.md ├── bin ├── ez └── ez-prod ├── box.json ├── composer.json ├── composer.lock ├── config ├── commands.yml └── services.yml ├── docs ├── CHANGELOG.md ├── LEMP_architecture.puml ├── css │ └── ezlaunchpad.css ├── ez.phar ├── ez.phar.pubkey ├── images │ └── puml │ │ ├── LAMP_architecture.png │ │ └── LEMP_architecture.png ├── index.html ├── install.bash ├── install_curl.bash ├── install_wget.bash ├── installer └── js │ ├── clipboard.min.js │ └── ezlaunchpad.js ├── payload ├── README.md ├── dev │ ├── docker-compose-osx.yml │ ├── docker-compose.yml │ ├── engine │ │ ├── Dockerfile │ │ ├── entrypoint.bash │ │ ├── php.ini │ │ └── xdebug.ini │ ├── nginx │ │ ├── entrypoint.bash │ │ ├── nginx.conf │ │ └── nginx_v2.conf │ ├── solr │ │ └── entrypoint.bash │ └── varnish │ │ └── varnish.vcl └── recipes │ ├── composer_install.bash │ ├── create_dump.bash │ ├── ez_create.bash │ ├── ez_install.bash │ ├── ez_install_solr.bash │ ├── ibexa_install.bash │ └── import_dump.bash ├── scripts ├── buildbox.bash ├── codechecker.bash ├── functions ├── pumltoimages.bash ├── runtests.bash └── travis_deploy.bash ├── src ├── Command │ ├── Docker │ │ ├── Build.php │ │ ├── Clean.php │ │ ├── ComposerRun.php │ │ ├── Create.php │ │ ├── DumpData.php │ │ ├── Enter.php │ │ ├── ImportData.php │ │ ├── Initialize.php │ │ ├── InitializeSkeleton.php │ │ ├── Logs.php │ │ ├── Restart.php │ │ ├── Start.php │ │ ├── Status.php │ │ ├── Stop.php │ │ ├── SymfonyRun.php │ │ ├── Up.php │ │ └── Update.php │ ├── Platformsh │ │ ├── Deploy.php │ │ └── Setup.php │ └── SelfUpdate.php ├── Configuration │ ├── Configuration.php │ └── Project.php ├── Console │ ├── Application.php │ └── ApplicationFactory.php ├── Core │ ├── Client │ │ └── Docker.php │ ├── Command.php │ ├── DockerCommand.php │ ├── DockerCompose.php │ ├── OSX │ │ └── Optimizer │ │ │ ├── D4M.php │ │ │ ├── NFSAwareInterface.php │ │ │ ├── NFSTrait.php │ │ │ ├── NFSVolumes.php │ │ │ ├── Optimizer.php │ │ │ └── OptimizerInterface.php │ ├── ProcessRunner.php │ ├── ProjectStatusDumper.php │ ├── ProjectWizard.php │ └── TaskExecutor.php ├── DependencyInjection │ └── CommandPass.php ├── Listener │ ├── ApplicationUpdate.php │ ├── CommandException.php │ ├── CommandStart.php │ ├── CommandTerminate.php │ └── OSXListener.php ├── bootstrap.php └── functions.php └── tests ├── Tests ├── Behat │ └── Commands │ │ ├── Context.php │ │ └── features │ │ └── test.feature ├── Command │ ├── Test.php │ └── TestDockerClient.php └── Unit │ ├── BehatTest.php │ ├── ConfigurationTest.php │ ├── DockerClientTest.php │ ├── DockerComposeTest.php │ ├── ProjectConfigurationTest.php │ ├── RequiredFilesTest.php │ ├── TaskExecutorTest.php │ └── TestCase.php ├── behat.yml ├── bootstrap.php ├── phpunit.xml.dist └── postman ├── collection-1x.json └── collection-2x.json /.cs/.php_cs.php: -------------------------------------------------------------------------------- 1 | in('src');//->in('tests'); 10 | 11 | return PhpCsFixer\Config::create() 12 | ->setRules( 13 | [ 14 | '@Symfony' => true, 15 | 'binary_operator_spaces' => [ 16 | 'align_equals' => false, 17 | 'align_double_arrow' => false, 18 | ], 19 | 'array_syntax' => ['syntax' => 'short'], 20 | 'pre_increment' => false, 21 | 'ordered_imports' => true, 22 | 'phpdoc_order' => true, 23 | 'linebreak_after_opening_tag' => true, 24 | 'phpdoc_no_package' => false, 25 | 'phpdoc_inline_tag' => false, 26 | 'cast_spaces' => false, 27 | 'no_superfluous_phpdoc_tags' => true, 28 | ] 29 | ) 30 | ->setFinder($finder); 31 | -------------------------------------------------------------------------------- /.cs/cs_ruleset.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | eZ Launchpad coding standard. 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /.cs/md_ruleset.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | eZ Launchpad Configuration 8 | 9 | 10 | 1 11 | 12 | 13 | 14 | 15 | 16 | 1 17 | 18 | 19 | 20 | 21 | 22 | 1 23 | 24 | 25 | 26 | 27 | 28 | 1 29 | 30 | 31 | 32 | 33 | 34 | 1 35 | 36 | 37 | 38 | 39 | 40 | 1 41 | 42 | 43 | 44 | 45 | 46 | 1 47 | 48 | 49 | 50 | 51 | 52 | 1 53 | 54 | 55 | 56 | 57 | 58 | 1 59 | 60 | 61 | 62 | 63 | 64 | 1 65 | 66 | 67 | 68 | 69 | 70 | 1 71 | 72 | 73 | 74 | 75 | 76 | 1 77 | 78 | 79 | 80 | 81 | 82 | 1 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [plopix] 2 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | | Q | A 2 | | ------------- | --- 3 | | Branch? | master / x.y.z 4 | | Bug fix? | yes/no 5 | | New feature? | yes/no 6 | | BC breaks? | yes/no 7 | | Fixed tickets | #... 8 | 9 | 16 | -------------------------------------------------------------------------------- /.github/issue_template.md: -------------------------------------------------------------------------------- 1 | | Q | A 2 | | ---------------- | ----- 3 | | Bug report? | yes/no 4 | | Feature request? | yes/no 5 | | BC Break report? | yes/no 6 | | RFC? | yes/no 7 | | Version | x.y.z 8 | | Environment | Linux/Mac/Windows 9 | 10 | 11 | 15 | -------------------------------------------------------------------------------- /.github/workflows/main-ci.yaml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | 7 | lint: 8 | name: Coding Standard 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v1 12 | - name: Setup PHP 13 | uses: shivammathur/setup-php@master 14 | with: 15 | php-version: 7.4 16 | id: php 17 | - name: Install dependencies 18 | run: composer install --prefer-dist --no-progress --no-suggest --no-interaction 19 | - name: Check Sources 20 | run: php vendor/bin/phpcs --standard=.cs/cs_ruleset.xml --extensions=php src/ 21 | - name: Check Tests 22 | run: php vendor/bin/phpcs --standard=.cs/cs_ruleset.xml --extensions=php src/ 23 | 24 | tests: 25 | name: Tests 26 | runs-on: ubuntu-latest 27 | strategy: 28 | matrix: 29 | php: [7.3, 7.4, 8.0] 30 | steps: 31 | - uses: actions/checkout@v1 32 | - name: Setup PHP 33 | uses: shivammathur/setup-php@master 34 | with: 35 | php-version: ${{ matrix.php }} 36 | id: php 37 | - name: Validate composer.json and composer.lock 38 | run: composer validate 39 | - name: Install dependencies 40 | run: composer install --prefer-dist --no-progress --no-suggest --no-interaction 41 | - name: Show Versions 42 | run: composer info -i 43 | - name: PHP Unit 44 | run: php vendor/bin/phpunit -c tests/ --exclude-group behat 45 | - name: Behat 46 | run: php vendor/behat/behat/bin/behat -c tests/behat.yml 47 | 48 | 49 | ezplatform: 50 | name: eZ Platform 51 | runs-on: ubuntu-latest 52 | strategy: 53 | matrix: 54 | php: [7.3, 7.4, 8.0] 55 | ezversion: [2.*, 3.*] 56 | collection: [collection-2x.json] 57 | steps: 58 | - uses: actions/checkout@v1 59 | - name: Setup PHP 60 | uses: shivammathur/setup-php@master 61 | with: 62 | php-version: ${{ matrix.php }} 63 | id: php 64 | - name: Install dependencies 65 | run: composer install --prefer-dist --no-progress --no-suggest --no-interaction 66 | - name: Initialization 67 | run: php bin/ez-prod init ezsystems/ezplatform ${{ matrix.ezversion }} --no-interaction -vvv 68 | - name: Status Info 69 | run: php bin/ez-prod ps 70 | - name: Verification using Postman 71 | run: 72 | docker run --net=host -v $(pwd)/tests/postman:/etc/newman -t postman/newman run ${{ matrix.collection }} 73 | 74 | ibexa: 75 | name: Ibexa 76 | runs-on: ubuntu-latest 77 | strategy: 78 | matrix: 79 | php: [7.4, 8.0] 80 | ezversion: [3.*] 81 | collection: [collection-2x.json] 82 | steps: 83 | - uses: actions/checkout@v1 84 | - name: Setup PHP 85 | uses: shivammathur/setup-php@master 86 | with: 87 | php-version: ${{ matrix.php }} 88 | id: php 89 | - name: Install dependencies 90 | run: composer install --prefer-dist --no-progress --no-suggest --no-interaction 91 | - name: Initialization 92 | run: php bin/ez-prod init ibexa/oss ${{ matrix.ezversion }} --no-interaction -vvv 93 | - name: Status Info 94 | run: php bin/ez-prod ps 95 | - name: Verification using Postman 96 | run: docker run --net=host -v $(pwd)/tests/postman:/etc/newman -t postman/newman run ${{ matrix.collection }} 97 | -------------------------------------------------------------------------------- /.github/workflows/release.yaml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | tags: 4 | - 'v*' 5 | 6 | name: Upload Phar 7 | 8 | jobs: 9 | build: 10 | name: Upload Phar 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@master 14 | - name: Install PROD dependencies ONLY 15 | run: composer install --prefer-dist --no-progress --no-suggest --no-interaction --no-dev 16 | - name: Build project 17 | env: 18 | EZ_LAUNCHPAD_PHAR_PRIVATE_KEY: ${{ secrets.EZ_LAUNCHPAD_PHAR_PRIVATE_KEY }} 19 | run: | 20 | echo "${EZ_LAUNCHPAD_PHAR_PRIVATE_KEY}" > ezlaunchpad-private.pem 21 | ulimit -Sn 4096 22 | curl -LSs https://box-project.github.io/box2/installer.php | php 23 | chmod 755 box.phar 24 | php -d "phar.readonly=false" ./box.phar build -vv 25 | rm ezlaunchpad-private.pem 26 | 27 | - name: Create Release 28 | id: create_release 29 | uses: actions/create-release@v1.0.0 30 | env: 31 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 32 | with: 33 | tag_name: ${{ github.ref }} 34 | release_name: Release ${{ github.ref }} 35 | draft: false 36 | prerelease: false 37 | 38 | - name: Upload Release Asset 39 | id: upload-release-asset 40 | uses: actions/upload-release-asset@v1.0.1 41 | env: 42 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 43 | with: 44 | upload_url: ${{ steps.create_release.outputs.upload_url }} 45 | asset_path: ./ez.phar 46 | asset_name: ez.phar 47 | asset_content_type: application/octet-stream 48 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /composer.phar 2 | /box.phar 3 | /ez.phar 4 | /ez.phar.* 5 | /vendor/ 6 | .php~ 7 | .idea 8 | .DS_Store 9 | *~ 10 | *.bak 11 | ._* 12 | ~* 13 | .php_cs.cache 14 | 15 | tests/coverage 16 | tests/.phpunit.result.cache 17 | 18 | # Auto-update 19 | /docs/ez-old.phar 20 | 21 | # Tests 22 | /provisioning 23 | /ezplatform 24 | /.ezlaunchpad.yml 25 | 26 | # CI stuff 27 | /build-key.pem 28 | /ezlaunchpad-private.pem 29 | /secrets.tar 30 | /plantuml.jar 31 | 32 | # others 33 | /provisioning2ouf 34 | /provisioning2 35 | /data 36 | 37 | # we do not want that at the root (usually generated when developing eZ Launchpad) 38 | /ez_install.bash 39 | /composer_install.bash 40 | /ez_install_solr.bash 41 | 42 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # eZ Launchpad 2 | 3 | This code of conduct outlines our expectations for participants within community. Anyone who violates this code of conduct may be banned from contributing here. 4 | 5 | ## Contributor Code of Conduct 6 | 7 | ### Our Pledge 8 | 9 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 10 | 11 | ### Our Standards 12 | 13 | Examples of behavior that contributes to creating a positive environment include: 14 | 15 | - Using welcoming and inclusive language 16 | - Being respectful of differing viewpoints and experiences 17 | - Gracefully accepting constructive criticism 18 | - Focusing on what is best for the community 19 | - Showing empathy towards other community members 20 | 21 | Examples of unacceptable behavior by participants include: 22 | 23 | - The use of sexualized language or imagery and unwelcome sexual attention or advances 24 | - Trolling, insulting/derogatory comments, and personal or political attacks 25 | - Public or private harassment 26 | - Publishing others' private information, such as a physical or electronic address, without explicit permission 27 | - Other conduct which could reasonably be considered inappropriate in a professional setting 28 | 29 | ### Our Responsibilities 30 | 31 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 32 | 33 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 34 | 35 | ### Scope 36 | 37 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 38 | 39 | ### Enforcement 40 | 41 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at info@ez.no. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 42 | 43 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 44 | 45 | ### Attribution 46 | 47 | This Code of Conduct is adapted from the Contributor Covenant, version 1.4, available at http://contributor-covenant.org/version/1/4. 48 | 49 | ## Contributing 50 | 51 | [CONTRIBUTING](CONTRIBUTING.md) 52 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # eZ Launchpad 2 | 3 | ## Contribution 4 | 5 | This project comes with Coding Standards and Tests. 6 | To help you contribute a Makefile is available to simplify the actions. 7 | 8 | ```bash 9 | $ make 10 | eZ Launchpad available targets: 11 | codeclean > run the codechecker 12 | tests > run the tests 13 | coverage > generate the code coverage 14 | install > install vendors 15 | clean > removes the vendors, caches, etc. 16 | phar > build the phar locally into your home 17 | ``` 18 | 19 | Please comply with `make codeclean` and `make tests` before to push, your PR won't be merged otherwise. 20 | 21 | > Note: the real *signed* .phar is generated on Travis and made available for all on Github after each merge on master. 22 | > Then there is no reason when you contribute to commit the .phar, it will be overriden at the merge. 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (C) eZ Systems AS. All rights reserved. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # === eZ Launchpad Helper === 2 | 3 | # Styles 4 | YELLOW=$(shell echo "\033[00;33m") 5 | RED=$(shell echo "\033[00;31m") 6 | RESTORE=$(shell echo "\033[0m") 7 | 8 | # Variables 9 | PHP_BIN := php 10 | COMPOSER_BIN := composer.phar 11 | DOCKER_BIN := docker 12 | SRCS := src 13 | CURRENT_DIR := $(shell pwd) 14 | SCRIPS_DIR := $(CURRENT_DIR)/scripts 15 | 16 | .DEFAULT_GOAL := list 17 | 18 | .PHONY: list 19 | list: 20 | @echo "******************************" 21 | @echo "${YELLOW}eZ Launchpad available targets${RESTORE}:" 22 | @grep -E '^[a-zA-Z-]+:.*?## .*$$' Makefile | sort | awk 'BEGIN {FS = ":.*?## "}; {printf " ${YELLOW}%-15s${RESTORE} > %s\n", $$1, $$2}' 23 | @echo "${RED}==============================${RESTORE}" 24 | 25 | .PHONY: install 26 | install: ## Install the vendor 27 | @composer install 28 | 29 | .PHONY: codeclean 30 | codeclean: ## Run the codechecker 31 | bash $(SCRIPS_DIR)/codechecker.bash 32 | 33 | .PHONY: tests 34 | tests: ## Run the tests 35 | bash $(SCRIPS_DIR)/runtests.bash 36 | 37 | .PHONY: behat 38 | behat: ## Run the Behat tests only 39 | bash $(SCRIPS_DIR)/runtests.bash behat 40 | 41 | .PHONY: unit 42 | unit: ## Run the Unit tests only 43 | bash $(SCRIPS_DIR)/runtests.bash unit 44 | 45 | .PHONY: convertpuml 46 | convertpuml: ## Convert PUML diagram in images 47 | bash $(SCRIPS_DIR)/pumltoimages.bash 48 | 49 | .PHONY: docs 50 | docs: ## Generate the documentation 51 | $(PHP_BIN) bin/gendocs 52 | 53 | .PHONY: phar 54 | phar: ## Build the box locally (bypass the PROD) 55 | bash $(SCRIPS_DIR)/buildbox.bash 56 | 57 | .PHONY: coverage 58 | coverage: ## Generate the code coverage 59 | rm -rf tests/coverage 60 | $(DOCKER_BIN) run -t --rm -w /app -v $(CURRENT_DIR):/app phpunit/phpunit:5.7.12 -c tests/ --coverage-html /app/tests/coverage 61 | 62 | .PHONY: clean 63 | clean: ## Removes the vendors, and caches 64 | rm -rf tests/coverage 65 | rm -f .php_cs.cache 66 | rm -f .ezlaunchpad.yml 67 | rm -rf vendor 68 | rm -rf ezplatform 69 | rm -rf provisioning 70 | rm -rf provisioning2ouf 71 | rm -f ezinstall.bash 72 | 73 | 74 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # eZ Launchpad 2 | 3 | eZ Launchpad is a CLI tool to start an eZ Platform project in 5 min on top of a full Docker stack. 4 | 5 | It's brought to you by, and supported by the eZ Community _(on ezcommunity.slack.com #ez-launchpad)_. 6 | 7 | You can find the full documentation here: https://ezsystems.github.io/launchpad 8 | 9 | | Branch | Travis build status | 10 | |:--------:|:-------------------:| 11 | | master | [![Build Status](https://travis-ci.org/ezsystems/launchpad.svg?branch=master)](https://travis-ci.org/ezsystems/launchpad) 12 | 13 | ## Contribution 14 | 15 | [CONTRIBUTING](CONTRIBUTING.md) 16 | 17 | ## License 18 | 19 | This project is under the MIT license. See the complete license in the file: 20 | 21 | [LICENSE](LICENSE) 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /bin/ez: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | run(); 17 | -------------------------------------------------------------------------------- /bin/ez-prod: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | run(); 17 | -------------------------------------------------------------------------------- /box.json: -------------------------------------------------------------------------------- 1 | { 2 | "algorithm": "OPENSSL", 3 | "alias": "ez.phar", 4 | "banner": "eZ Launchpad", 5 | "chmod": "0755", 6 | "compression": "GZ", 7 | "compactors": [ 8 | "Herrera\\Box\\Compactor\\Json", 9 | "Herrera\\Box\\Compactor\\Php" 10 | ], 11 | "directories": [ 12 | "src", 13 | "config", 14 | "payload" 15 | ], 16 | "files": [ 17 | "LICENSE" 18 | ], 19 | "finder": [ 20 | { 21 | "name": "*.php", 22 | "exclude": [ 23 | "tests", 24 | "Tests" 25 | ], 26 | "in": "vendor" 27 | } 28 | ], 29 | "git-tag": "package_version", 30 | "main": "bin/ez-prod", 31 | "key": "ezlaunchpad-private.pem", 32 | "output": "ez.phar", 33 | "stub": true 34 | } 35 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ezsystems/launchpad", 3 | "description": "eZ Launchpad - Ultimate eZ Platform CLI Helper.", 4 | "homepage": "https://github.com/ezsystems/launchpad", 5 | "require": { 6 | "php": "^7.2.5", 7 | "symfony/console": "^5.1", 8 | "symfony/yaml": "^5.1", 9 | "symfony/dependency-injection": "^5.1", 10 | "symfony/process": "^5.1", 11 | "symfony/finder": "^5.1", 12 | "symfony/config": "^5.1", 13 | "symfony/filesystem": "^5.1", 14 | "novactive/collection": "^1.1.0", 15 | "symfony/options-resolver": "^5.1", 16 | "symfony/event-dispatcher": "^5.1", 17 | "nesbot/carbon": "^2" 18 | }, 19 | "require-dev": { 20 | "symfony/var-dumper": "^5.1", 21 | "friendsofphp/php-cs-fixer": "^2.14", 22 | "phpmd/phpmd": "^2.6", 23 | "squizlabs/php_codesniffer": "^3.4", 24 | "phpunit/phpunit": "^8", 25 | "behat/behat": "^3.7", 26 | "mikey179/vfsstream": "^1.6", 27 | "twig/twig": "^3", 28 | "symfony/translation": "^5.1", 29 | "symfony/twig-bridge": "^5.1" 30 | }, 31 | "config": { 32 | "platform": { 33 | "php": "7.2.5" 34 | } 35 | }, 36 | "autoload": { 37 | "psr-4": { 38 | "eZ\\Launchpad\\": "src/" 39 | }, 40 | "files": [ 41 | "src/functions.php" 42 | ] 43 | }, 44 | "prefer-stable": true, 45 | "autoload-dev": { 46 | "psr-4": { 47 | "eZ\\Launchpad\\Tests\\": "tests/Tests" 48 | } 49 | }, 50 | "bin": [ 51 | "bin/ez" 52 | ] 53 | } 54 | -------------------------------------------------------------------------------- /config/commands.yml: -------------------------------------------------------------------------------- 1 | --- 2 | services: 3 | 4 | _defaults: 5 | autowire: true 6 | public: true 7 | 8 | _instanceof: 9 | eZ\Launchpad\Core\Command: 10 | tags: [ezlaunchpad.command] 11 | 12 | # Not working in a Phar (method glob() is used but it is not working in a phar) 13 | #eZ\Launchpad\Command\: 14 | # resource: ../src/Command/* 15 | 16 | # then we need to list them manually 17 | eZ\Launchpad\Command\Rollback: ~ 18 | eZ\Launchpad\Command\Docker\Start: ~ 19 | eZ\Launchpad\Command\Docker\Stop: ~ 20 | eZ\Launchpad\Command\Docker\Up: ~ 21 | eZ\Launchpad\Command\Docker\Clean: ~ 22 | eZ\Launchpad\Command\Docker\Status: ~ 23 | eZ\Launchpad\Command\Docker\Enter: ~ 24 | eZ\Launchpad\Command\Docker\Logs: ~ 25 | eZ\Launchpad\Command\Docker\SymfonyRun: ~ 26 | eZ\Launchpad\Command\Docker\ComposerRun: ~ 27 | eZ\Launchpad\Command\Platformsh\Deploy: ~ 28 | 29 | # Self 30 | eZ\Launchpad\Command\SelfUpdate: 31 | calls: 32 | - [setParameters, [ {release_url: "%github_release_url%"} ] ] 33 | 34 | # Docker 35 | eZ\Launchpad\Command\Docker\Update: 36 | calls: 37 | - [setRequiredRecipes, [ [ 'composer_install' ] ] ] 38 | 39 | eZ\Launchpad\Command\Docker\Build: 40 | calls: 41 | - [setRequiredRecipes, [ [ 'composer_install' ] ] ] 42 | 43 | eZ\Launchpad\Command\Docker\Initialize: 44 | calls: 45 | - [setRequiredRecipes, [ [ 'composer_install', 'ez_install', 'ibexa_install', 'ez_install_solr' ] ] ] 46 | 47 | eZ\Launchpad\Command\Docker\InitializeSkeleton: 48 | calls: 49 | - [setRequiredRecipes, [ [ 'composer_install' ] ] ] 50 | 51 | eZ\Launchpad\Command\Docker\Create: 52 | calls: 53 | - [setRequiredRecipes, [ [ 'composer_install', 'ez_create', 'import_dump', 'ez_install_solr' ] ] ] 54 | 55 | eZ\Launchpad\Command\Docker\DumpData: 56 | calls: 57 | - [setRequiredRecipes, [ [ 'create_dump' ] ] ] 58 | 59 | eZ\Launchpad\Command\Docker\ImportData: 60 | calls: 61 | - [setRequiredRecipes, [ [ 'import_dump' ] ] ] 62 | 63 | # Platform.sh 64 | eZ\Launchpad\Command\Platformsh\Setup: 65 | calls: 66 | - [setRequiredRecipes, [ [ 'create_dump' ] ] ] 67 | -------------------------------------------------------------------------------- /config/services.yml: -------------------------------------------------------------------------------- 1 | --- 2 | parameters: 3 | github_release_url: "https://api.github.com/repos/ezsystems/launchpad/releases?draft=false&prerelease=false" 4 | 5 | services: 6 | 7 | _defaults: 8 | autowire: true 9 | public: true 10 | 11 | eZ\Launchpad\Listener\ApplicationUpdate: 12 | arguments: 13 | - {release_url: "%github_release_url%"} 14 | tags: 15 | - { name: kernel.event_listener, event: console.command, method: onCommandAction } 16 | 17 | eZ\Launchpad\Listener\CommandException: 18 | tags: 19 | - { name: kernel.event_listener, event: console.error, method: onExceptionAction } 20 | 21 | eZ\Launchpad\Listener\CommandStart: 22 | tags: 23 | - { name: kernel.event_listener, event: console.command, method: onCommandAction } 24 | 25 | 26 | eZ\Launchpad\Listener\CommandTerminate: 27 | tags: 28 | - { name: kernel.event_listener, event: console.terminate, method: onTerminateAction } 29 | 30 | eZ\Launchpad\Core\ProjectStatusDumper: ~ 31 | 32 | eZ\Launchpad\Listener\OSXListener: 33 | class: 34 | arguments: [!tagged ezlaunchpad.osx.optimizer] 35 | tags: 36 | - { name: kernel.event_listener, event: console.command, method: onCommandAction } 37 | 38 | # OSX OPTIMIZER 39 | eZ\Launchpad\Core\OSX\Optimizer\D4M: 40 | tags: [ezlaunchpad.osx.optimizer] 41 | 42 | eZ\Launchpad\Core\OSX\Optimizer\NFSVolumes: 43 | tags: [ezlaunchpad.osx.optimizer] 44 | -------------------------------------------------------------------------------- /docs/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # eZ Launchpad 2 | 3 | ## CHANGELOG 4 | 5 | ### ?.?.? 6 | 7 | - Add support for calling composer ezplatform-install (script) on "initialdata" argument 8 | - Add support for xdebug 9 | 10 | 11 | ### 1.4.0 12 | 13 | - Add SOLR_CORES env variable on solr container to define the core(s) name. (default = "collection1") 14 | - Add DATABASE_PREFIXES env variable on engine container. This var define the prefix used to name the db connection vars (default = "DATABASE"). It's possible to define multiple prefixes to handle multiple db. 15 | - Remove composer.phar manipulation and add composer in the engine image. 16 | 17 | ### 1.3.0 18 | 19 | - First version ready for 2.x with the new directory structure 20 | 21 | ### 1.2.1 22 | 23 | - Apply EZP-28183 change 24 | 25 | ### 1.2.0 26 | 27 | - use Redis for Session for Platform.sh configuration by default 28 | - Wizard Simplification, to remove the questions in 'standard' mode 29 | - Fix TCP port mapping with Memached Admin 30 | 31 | ### 1.1.0 32 | 33 | - ezplatform-http-cache is enabled when not loaded 34 | - Varnish5 and xkey VCL by default 35 | - new Default README.md after initialize 36 | - Simpler Makefile 37 | - Cache are now purged when using Varnish (new ENV var trigger ezplatform to do it) 38 | - Platform.sh optimizations 39 | - Docker-Compose file is more readable 40 | - Fix #7 41 | - Fix #8 42 | 43 | 44 | ### 1.0.0 45 | 46 | - Initial Stable Version 47 | -------------------------------------------------------------------------------- /docs/LEMP_architecture.puml: -------------------------------------------------------------------------------- 1 | @startuml 2 | 3 | title "Development Architecture - LEMP" 4 | 5 | cloud "Exposed Ports" { 6 | () XX080 as SymfonyDevModePort 7 | () XX081 as SymfonyProdModePort 8 | () XX082 as SymfonyProdModeVarnishPort 9 | 10 | () XX083 as RedisAdminPort 11 | () XX983 as SorlPort 12 | () XX084 as DatabaseAdminPort 13 | () XX306 as DatabaseEnginePort 14 | () XX180 as MailcatcherPort 15 | } 16 | 17 | node "nginx" { 18 | [PROD] 19 | [DEV] 20 | } 21 | 22 | node "Engine" as engine { 23 | [PHP-FPM] as PhpFPM 24 | [PHP-CLI] as PhpCli 25 | } 26 | 27 | node "MySQL or MariaDB" as db { 28 | database "ezplatform" as StandardDB 29 | } 30 | 31 | node "Redis" as appcache { 32 | } 33 | 34 | node "Varnish 4.x" as varnish { 35 | } 36 | 37 | node "Redis Admin" as redisadmin { 38 | } 39 | 40 | node "Mailcatcher" as mailcatcher { 41 | } 42 | 43 | node "Adminer" as dbadmin { 44 | } 45 | 46 | node "Solr" as solr { 47 | } 48 | 49 | RedisAdminPort -> redisadmin: Web Interface 50 | DatabaseEnginePort ---> db: TCP forward 51 | MailcatcherPort -> mailcatcher: Web Interface 52 | DatabaseAdminPort --> dbadmin: Web Interface 53 | SorlPort -> solr 54 | 55 | SymfonyDevModePort --> DEV: Web 56 | SymfonyProdModePort --> PROD: Web 57 | SymfonyProdModeVarnishPort --> varnish: Web 58 | varnish --> PROD 59 | 60 | DEV --> PhpFPM 61 | PROD --> PhpFPM 62 | 63 | engine -up--> db 64 | engine --> appcache 65 | engine --> mailcatcher 66 | engine ---> solr 67 | 68 | redisadmin --> appcache 69 | dbadmin ---> db 70 | 71 | @enduml 72 | -------------------------------------------------------------------------------- /docs/css/ezlaunchpad.css: -------------------------------------------------------------------------------- 1 | 2 | a, a:hover, h1 i,h2 i,h3 i,h4 i,h5 i,h6 i { 3 | color: #E61851; 4 | } 5 | 6 | 7 | .container .text-muted { 8 | margin: 20px 0; 9 | } 10 | 11 | .highlight { 12 | position: relative; 13 | } 14 | 15 | .highlight .to-clipboard { 16 | position: absolute; 17 | top: 0; 18 | right: 0; 19 | z-index: 10; 20 | display: block; 21 | padding: 5px 8px; 22 | font-size: 12px; 23 | color: #767676; 24 | cursor: pointer; 25 | background-color: #fff; 26 | border: 1px solid #e1e1e8; 27 | border-radius: 0 4px 0 4px; 28 | } 29 | 30 | .ezlp-submenu li, .ezlp-submenu li a { 31 | height: auto; 32 | } 33 | 34 | .clickable { 35 | cursor:pointer; 36 | } 37 | 38 | .footer-content { 39 | color: #f2f2f2; 40 | background-color: #000; 41 | padding-top: 50px; 42 | padding-bottom: 50px; 43 | } 44 | 45 | .footer-content a { 46 | color: #fff; 47 | text-decoration: none; 48 | } 49 | 50 | .copyright-content { 51 | background-color: #666; 52 | color: #BFBFBF; 53 | padding-top: 20px; 54 | padding-bottom: 20px; 55 | } 56 | 57 | .copyright-content a, .copyright-content a:hover { 58 | color: #ff4713; 59 | } 60 | -------------------------------------------------------------------------------- /docs/ez.phar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ezsystems/launchpad/f5704fc0399dc1977e0b3ed12de734a34e1be00f/docs/ez.phar -------------------------------------------------------------------------------- /docs/ez.phar.pubkey: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAzzMKkvmPQvqdPGax6BQz 3 | Wd4U3M2O2s/bgbX2KF5sXWitSzccrnoje2TIcWfhnRZXiqcgbagxconI2V3WJP7U 4 | oiZ2iqhJs3WqEdciYmX8tdc3JMAMaNMkhpEDcJcXnhYVuoA/i2Ad3RAfnW/XIUYy 5 | anD3VQNZTdu/oolhv5/kbMQdUFaf5NnI+j13qPQjoaqNOZh/5CaOkRYUnDdNPn7C 6 | vzyF9YQ3nW5wSrWR9TqkvIeVoJ/4kdemeEh+DYZZlNa55f/nPkW2SXiXC4UJfbA/ 7 | EkfAJWSdJNR73XtCqen96BV8zeE0VsVGouPRFtKasNCPkhsUzpbf77QNnESatuDi 8 | gaoYWZCRQJ3tmgQBV4o35H2ZI36mz48z2vUuqdtb4ONTKtc5yEZZNiqfDARAys5a 9 | nr4V3CGifCoMq/2bmF4QxDc0//J7aDV63dc3W+b7dYOoCs5RvPLSAzei7QCvQmwN 10 | 3ihCp5qJurqm4boZVTiEtwGMKYPe04gHQKivwB196wBLMhgMpAw7tBebG6uJl2i2 11 | 0oe08WAASJ7agiE04gM0+0e4xHXopTfOjYtiLm4khLtHm4vORoCbX1hm+ZYo8fL5 12 | ynl9opd2vopwukVIC2t2WXGa/0SLVcygnjq4ow4it6zq+zPemS/AiR23//UMKr8h 13 | gkX9cNgYQNT9Ko+Plqe+kT8CAwEAAQ== 14 | -----END PUBLIC KEY----- 15 | -------------------------------------------------------------------------------- /docs/images/puml/LAMP_architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ezsystems/launchpad/f5704fc0399dc1977e0b3ed12de734a34e1be00f/docs/images/puml/LAMP_architecture.png -------------------------------------------------------------------------------- /docs/images/puml/LEMP_architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ezsystems/launchpad/f5704fc0399dc1977e0b3ed12de734a34e1be00f/docs/images/puml/LEMP_architecture.png -------------------------------------------------------------------------------- /docs/install.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | EZ_HOME="$HOME/.ezlaunchpad" 4 | mkdir -p $EZ_HOME 5 | cd $EZ_HOME 6 | 7 | php -r "copy('https://ezsystems.github.io/launchpad/installer', 'installer');" 8 | php installer 9 | rm installer 10 | 11 | ln -sf $EZ_HOME/ez.phar $HOME/ez 12 | chmod +x $HOME/ez 13 | 14 | echo "You can now use eZ Launchpad by running: ~/ez" 15 | echo "" 16 | echo "- You may want to put ~/ez in you PATH" 17 | echo "- You may want to creat an alias (in your .zshrc or .bashrc) alias ez='~/ez'" 18 | 19 | ~/ez 20 | -------------------------------------------------------------------------------- /docs/install_curl.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # @see: install.bash, this one is a copy/paste to avoid BC break 4 | 5 | EZ_HOME="$HOME/.ezlaunchpad" 6 | mkdir -p $EZ_HOME 7 | cd $EZ_HOME 8 | 9 | php -r "copy('https://ezsystems.github.io/launchpad/installer', 'installer');" 10 | php installer 11 | rm installer 12 | 13 | ln -sf $EZ_HOME/ez.phar $HOME/ez 14 | chmod +x $HOME/ez 15 | 16 | echo "You can now use eZ Launchpad by running: ~/ez" 17 | echo "" 18 | echo "- You may want to put ~/ez in you PATH" 19 | echo "- You may want to creat an alias (in your .zshrc or .bashrc) alias ez='~/ez'" 20 | 21 | ~/ez 22 | -------------------------------------------------------------------------------- /docs/install_wget.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # @see: install.bash, this one is a copy/paste to avoid BC break 4 | 5 | EZ_HOME="$HOME/.ezlaunchpad" 6 | mkdir -p $EZ_HOME 7 | cd $EZ_HOME 8 | 9 | php -r "copy('https://ezsystems.github.io/launchpad/installer', 'installer');" 10 | php installer 11 | rm installer 12 | 13 | ln -sf $EZ_HOME/ez.phar $HOME/ez 14 | chmod +x $HOME/ez 15 | 16 | echo "You can now use eZ Launchpad by running: ~/ez" 17 | echo "" 18 | echo "- You may want to put ~/ez in you PATH" 19 | echo "- You may want to creat an alias (in your .zshrc or .bashrc) alias ez='~/ez'" 20 | 21 | ~/ez 22 | -------------------------------------------------------------------------------- /docs/installer: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | [ 13 | 'method' => 'GET', 14 | 'header' => [ 15 | 'User-Agent: eZ Launchpad Installer' 16 | ] 17 | ] 18 | ] 19 | ); 20 | $release = json_decode( 21 | file_get_contents( 22 | "https://api.github.com/repos/{$repo}/releases?draft=false&prerelease=false", 23 | false, 24 | $context 25 | ), 26 | false 27 | )[0]; 28 | 29 | unset($content); 30 | $assetUrl = $release->assets[0]->browser_download_url; 31 | 32 | file_put_contents( 33 | "ez.phar", 34 | file_get_contents( 35 | $assetUrl, 36 | false, 37 | $context 38 | ) 39 | ); 40 | 41 | file_put_contents( 42 | "ez.phar.pubkey", 43 | file_get_contents( 44 | "https://ezsystems.github.io/launchpad/ez.phar.pubkey", 45 | false, 46 | $context 47 | ) 48 | ); 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /docs/js/ezlaunchpad.js: -------------------------------------------------------------------------------- 1 | $(function () { 2 | var clipboard = new Clipboard('button.to-clipboard', { 3 | text: function (trigger) { 4 | return $(trigger).parent().find("code:first").text(); 5 | } 6 | }); 7 | clipboard.on('success', function (e) { 8 | var $trigger = $(e.trigger); 9 | $trigger.text("Copied!"); 10 | setTimeout(function () { 11 | $trigger.html(' Copy'); 12 | }, 3000); 13 | e.clearSelection(); 14 | }); 15 | 16 | }); 17 | -------------------------------------------------------------------------------- /payload/README.md: -------------------------------------------------------------------------------- 1 | eZ with eZ Launchpad 2 | ==================== 3 | 4 | This project has been generated by eZ Launchpad. 5 | 6 | You can find the full documentation here: https://ezsystems.github.io/launchpad 7 | 8 | You can find the Launchpad repository here: https://github.com/ezsystems/launchpad 9 | 10 | ## Install and use 11 | 12 | 1. Install the launchpad with **curl** OR **wget**: 13 | ```sh 14 | $ curl -LSs https://ezsystems.github.io/launchpad/install_curl.bash | bash 15 | 16 | # OR 17 | 18 | $ wget -O - "https://ezsystems.github.io/launchpad/install_wget.bash" | bash 19 | ``` 20 | 21 | 2. Start the docker containers: 22 | ```sh 23 | $ ~/ez start 24 | ``` 25 | 26 | 3. Load data: 27 | ``` 28 | $ ~/ez importdata 29 | ``` 30 | 31 | 4. Ready to use and develop: 32 | ``` 33 | # View containers: 34 | $ ~/ez ps 35 | 36 | # Enter the engine container: 37 | $ ~/ez enter 38 | 39 | # Full command and alias list: 40 | $ ~/ez 41 | ``` 42 | -------------------------------------------------------------------------------- /payload/dev/docker-compose-osx.yml: -------------------------------------------------------------------------------- 1 | version: '2.2' 2 | services: 3 | engine: 4 | volumes: 5 | - "nfsmount:${PROJECTMAPPINGFOLDER}" 6 | volumes: 7 | nfsmount: 8 | driver: local 9 | driver_opts: 10 | type: nfs 11 | o: addr=host.docker.internal,rw,nolock,hard,nointr,nfsvers=3 12 | device: ":${PROJECTCOMPOSEPATH}/" 13 | -------------------------------------------------------------------------------- /payload/dev/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2.2' 2 | services: 3 | nginx: 4 | image: nginx:stable-alpine 5 | volumes: 6 | - "${PROJECTCOMPOSEPATH}/${PROVISIONINGFOLDERNAME}/dev/nginx/nginx.conf:/etc/nginx/conf.d/default.conf:ro" 7 | - "${PROJECTCOMPOSEPATH}/${PROVISIONINGFOLDERNAME}/dev/nginx/entrypoint.bash:/entrypoint.bash:ro" 8 | - "${PROJECTCOMPOSEPATH}/ezplatform/doc/nginx/ez_params.d:/etc/nginx/ez_params.d:ro" 9 | depends_on: 10 | - engine 11 | volumes_from: 12 | - engine:ro 13 | entrypoint: /entrypoint.bash 14 | ports: 15 | - "${PROJECTPORTPREFIX}080:80" 16 | - "${PROJECTPORTPREFIX}081:81" 17 | environment: 18 | - PROJECTMAPPINGFOLDER 19 | 20 | engine: 21 | build: ./engine/ 22 | volumes: 23 | - "${PROJECTCOMPOSEPATH}/${PROVISIONINGFOLDERNAME}/dev/engine/php.ini:/usr/local/etc/php/php.ini:ro" 24 | - "${PROJECTCOMPOSEPATH}:${PROJECTMAPPINGFOLDER}:rw" 25 | - "${HOST_COMPOSER_CACHE_DIR}:${COMPOSER_CACHE_DIR}:rw" 26 | - "${PROJECTCOMPOSEPATH}/${PROVISIONINGFOLDERNAME}/dev/solr:/ezsolr:rw" 27 | shm_size: 754M 28 | environment: 29 | - COMPOSER_CACHE_DIR 30 | - PROJECTMAPPINGFOLDER 31 | - DEV_UID 32 | - DEV_GID 33 | - XDEBUG_ENABLED 34 | - "XDEBUG_CONFIG=remote_host=172.17.0.1" 35 | - "PHP_IDE_CONFIG=serverName=ezplatform" 36 | - "EZP_TEST_REST_HOST=nginx" 37 | - "DATABASE_PREFIXES=DATABASE" 38 | - "DATABASE_PLATFORM=mysql" 39 | - "DATABASE_DRIVER=pdo_mysql" 40 | - "DATABASE_USER=root" 41 | - "DATABASE_NAME=ezplatform" 42 | - "DATABASE_PASSWORD=ezplatform" 43 | - "SYMFONY_SECRET=eZlaunchpad20Secret09Dev83ModeZ" 44 | - "APP_SECRET=eZlaunchpad20Secret09Dev83ModeZ" 45 | - "DATABASE_HOST=db" 46 | - "CUSTOM_CACHE_POOL=singleredis" 47 | - "CACHE_HOST=redis" 48 | - "CACHE_REDIS_PORT=6379" 49 | - "CACHE_POOL=cache.redis" 50 | - "CACHE_DSN=redis:6379" 51 | - "SEARCH_ENGINE=solr" 52 | - "SOLR_DSN=http://solr:8983/solr" 53 | - "SYMFONY_TMP_DIR=/tmp/ezplatformcache/" 54 | - "APP_CACHE_DIR=/tmp/ezplatformcache/" 55 | - "APP_LOG_DIR=/tmp/ezplatformlogs/" 56 | - "HTTPCACHE_VARNISH_INVALIDATE_TOKEN=eZlaunchpad20Secret09Varnish" 57 | - "SESSION_HANDLER_ID=ezplatform.core.session.handler.native_redis" 58 | - "SESSION_SAVE_PATH=tcp://redis:6379" 59 | db: 60 | image: mariadb:10.3 61 | environment: 62 | - "MYSQL_ROOT_PASSWORD=ezplatform" 63 | ports: 64 | - "${PROJECTPORTPREFIX}306:3306" 65 | 66 | varnish: 67 | image: plopix/docker-varnish6 68 | volumes: 69 | - "${PROJECTCOMPOSEPATH}/${PROVISIONINGFOLDERNAME}/dev/varnish/varnish.vcl:/etc/varnish/default.vcl:ro" 70 | ports: 71 | - "${PROJECTPORTPREFIX}082:80" 72 | depends_on: 73 | - nginx 74 | 75 | solr: 76 | image: solr:7.7 77 | volumes: 78 | - "${PROJECTCOMPOSEPATH}/${PROVISIONINGFOLDERNAME}/dev/solr/entrypoint.bash:/entrypoint.bash:ro" 79 | volumes_from: 80 | - engine:rw 81 | ports: 82 | - "${PROJECTPORTPREFIX}983:8983" 83 | entrypoint: /entrypoint.bash 84 | depends_on: 85 | - engine 86 | environment: 87 | - DEV_UID 88 | - DEV_GID 89 | - PROJECTMAPPINGFOLDER 90 | - SOLR_CORES=collection1 91 | 92 | # Mailcatcher 93 | mailcatcher: 94 | image: schickling/mailcatcher 95 | ports: 96 | - "${PROJECTPORTPREFIX}180:1080" 97 | 98 | # Adminer 99 | adminer: 100 | image: adminer:latest 101 | ports: 102 | - "${PROJECTPORTPREFIX}084:8080" 103 | 104 | # REDIS 105 | redis: 106 | image: redis:latest 107 | depends_on: 108 | - engine 109 | 110 | redisadmin: 111 | image: rediscommander/redis-commander:latest 112 | environment: 113 | - REDIS_HOST=redis 114 | ports: 115 | - "${PROJECTPORTPREFIX}083:8081" 116 | 117 | # Blackfire 118 | blackfire: 119 | image: blackfire/blackfire 120 | environment: 121 | - BLACKFIRE_CLIENT_ID 122 | - BLACKFIRE_CLIENT_TOKEN 123 | - BLACKFIRE_SERVER_ID 124 | - BLACKFIRE_SERVER_TOKEN 125 | 126 | # Mysql-Proxy 127 | mysqlproxy: 128 | image: plopix/docker-mysqlproxyprofiler 129 | environment: 130 | - 'BACKEND=db:3306' 131 | -------------------------------------------------------------------------------- /payload/dev/engine/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM plopix/docker-php-ez-engine:7.4 2 | MAINTAINER Plopix 3 | 4 | ENV XDEBUG_ENABLED=0 5 | 6 | RUN mkdir /usr/local/etc/php/enable-xdebug 7 | 8 | COPY xdebug.ini /usr/local/etc/php/enable-xdebug/99-xdebug.ini 9 | 10 | COPY entrypoint.bash /entrypoint.bash 11 | RUN chmod +x /entrypoint.bash 12 | ENTRYPOINT ["/entrypoint.bash"] 13 | CMD ["php-fpm"] 14 | -------------------------------------------------------------------------------- /payload/dev/engine/entrypoint.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ORIGPASSWD=$(cat /etc/passwd | grep www-data) 4 | ORIG_UID=$(echo "$ORIGPASSWD" | cut -f3 -d:) 5 | ORIG_GID=$(echo "$ORIGPASSWD" | cut -f4 -d:) 6 | ORIG_HOME=$(echo "$ORIGPASSWD" | cut -f6 -d:) 7 | DEV_UID=${DEV_UID:=$ORIG_UID} 8 | DEV_GID=${DEV_GID:=$ORIG_GID} 9 | 10 | if [ "$DEV_UID" -ne "$ORIG_UID" ] || [ "$DEV_GID" -ne "$ORIG_GID" ]; then 11 | groupmod -g "$DEV_GID" www-data 12 | usermod -u "$DEV_UID" -g "$DEV_GID" www-data 13 | fi 14 | 15 | # Create .composer in advance and set the permissions 16 | mkdir -p /var/www/.composer && chown www-data:www-data /var/www/.composer 17 | chown www-data:www-data $PROJECTMAPPINGFOLDER 18 | 19 | # give the good permissions to www-data in the container and remove the cache on start 20 | # 2.x 21 | if [ -d $PROJECTMAPPINGFOLDER/ezplatform/var/cache ]; then 22 | rm -rf $PROJECTMAPPINGFOLDER/ezplatform/var/cache 23 | rm -rf $SYMFONY_TMP_DIR/var/cache 24 | chown -R www-data:www-data $PROJECTMAPPINGFOLDER/ezplatform/var/logs 25 | chown -R www-data:www-data $PROJECTMAPPINGFOLDER/ezplatform/web 26 | fi 27 | 28 | if [ ! -f /usr/local/bin/composer ]; 29 | then 30 | echo "WARNING: you don't have the last image of the PHP ENGINE" 31 | echo "TO FIX RUN: ~/ez docker:update" 32 | fi 33 | /usr/local/bin/composer self-update --1 34 | 35 | if [ "1" = "${XDEBUG_ENABLED}" ]; then 36 | export PHP_INI_SCAN_DIR=:/usr/local/etc/php/enable-xdebug 37 | fi 38 | 39 | exec "$@" 40 | -------------------------------------------------------------------------------- /payload/dev/engine/php.ini: -------------------------------------------------------------------------------- 1 | disable_functions = 2 | disable_classes = 3 | 4 | max_execution_time = 120 5 | max_input_time = 90 6 | 7 | display_errors = "On" 8 | log_errors = "On" 9 | 10 | memory_limit = 2048M 11 | post_max_size = 40M 12 | upload_max_filesize = 40M 13 | 14 | session.save_handler = redis 15 | session.save_path = "tcp://redis:6379" 16 | 17 | sendmail_path = /usr/bin/env catchmail --smtp-ip mailcatcher --smtp-port 1025 -f docker@localhost 18 | 19 | extension=blackfire.so 20 | blackfire.agent_socket=tcp://blackfire:8707 21 | 22 | [Date] 23 | date.timezone = "America/Los_Angeles" 24 | 25 | 26 | -------------------------------------------------------------------------------- /payload/dev/engine/xdebug.ini: -------------------------------------------------------------------------------- 1 | zend_extension=/usr/local/lib/php/extensions/no-debug-non-zts-20190902/xdebug.so 2 | xdebug.default_enable=1 3 | xdebug.remote_enable=1 4 | xdebug.max_nesting_level=1000 5 | xdebug.idekey=XDEBUG_IDE_KEY 6 | xdebug.remote_connect_back=1 7 | -------------------------------------------------------------------------------- /payload/dev/nginx/entrypoint.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ash 2 | 3 | nginx -g "daemon off;" 4 | -------------------------------------------------------------------------------- /payload/dev/nginx/nginx.conf: -------------------------------------------------------------------------------- 1 | # GZIP 2 | gzip on; 3 | gzip_disable "msie6"; 4 | gzip_proxied any; 5 | gzip_comp_level 6; 6 | gzip_buffers 16 8k; 7 | gzip_http_version 1.1; 8 | gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript; 9 | 10 | # DEV MODE 11 | server { 12 | listen 80; 13 | server_name _; 14 | # Project Root = project-path-container = /var/www/html/project 15 | # Would be great to get that from ENV var PROJECTMAPPINGFOLDER 16 | root "/var/www/html/project/ezplatform/public"; 17 | 18 | # FOR DFS 19 | # include ez_params.d/ez_rewrite_dfsimage_params; 20 | 21 | # ez rewrite rules 22 | include ez_params.d/ez_rewrite_params; 23 | 24 | # upload max size 25 | client_max_body_size 40M; 26 | 27 | # FPM fastcgi_read_timeout 28 | fastcgi_read_timeout 30; 29 | 30 | location / { 31 | location ~ ^/index\.php(/|$) { 32 | include ez_params.d/ez_fastcgi_params; 33 | fastcgi_pass engine:9000; 34 | fastcgi_param APP_ENV dev; 35 | fastcgi_param RUNNING_ENV DOCKER; 36 | } 37 | } 38 | include ez_params.d/ez_server_params; 39 | } 40 | 41 | # PROD MODE - Symfony Reverse Proxy 42 | server { 43 | listen 81; 44 | server_name _; 45 | # Project Root = project-path-container = /var/www/html/project 46 | # Would be great to get that from ENV var PROJECTMAPPINGFOLDER 47 | root "/var/www/html/project/ezplatform/public"; 48 | 49 | include ez_params.d/ez_prod_rewrite_params; 50 | 51 | # FOR DFS 52 | # include ez_params.d/ez_rewrite_dfsimage_params; 53 | 54 | # ez rewrite rules 55 | include ez_params.d/ez_rewrite_params; 56 | 57 | # upload max size 58 | client_max_body_size 40M; 59 | 60 | # FPM fastcgi_read_timeout 61 | fastcgi_read_timeout 30; 62 | 63 | location / { 64 | location ~ ^/index\.php(/|$) { 65 | include ez_params.d/ez_fastcgi_params; 66 | 67 | fastcgi_pass engine:9000; 68 | fastcgi_param APP_ENV prod; 69 | fastcgi_param RUNNING_ENV DOCKER; 70 | } 71 | } 72 | include ez_params.d/ez_server_params; 73 | } 74 | 75 | 76 | # PROD MODE - Varnish 77 | server { 78 | listen 82; 79 | server_name _; 80 | # Project Root = project-path-container = /var/www/html/project 81 | # Would be great to get that from ENV var PROJECTMAPPINGFOLDER 82 | root "/var/www/html/project/ezplatform/public"; 83 | 84 | include ez_params.d/ez_prod_rewrite_params; 85 | 86 | # FOR DFS 87 | # include ez_params.d/ez_rewrite_dfsimage_params; 88 | 89 | # ez rewrite rules 90 | include ez_params.d/ez_rewrite_params; 91 | 92 | # upload max size 93 | client_max_body_size 40M; 94 | 95 | # FPM fastcgi_read_timeout 96 | fastcgi_read_timeout 30; 97 | 98 | location / { 99 | location ~ ^/index\.php(/|$) { 100 | include ez_params.d/ez_fastcgi_params; 101 | 102 | fastcgi_pass engine:9000; 103 | fastcgi_param APP_ENV prod; 104 | fastcgi_param RUNNING_ENV DOCKER; 105 | fastcgi_param APP_HTTP_CACHE 0; 106 | fastcgi_param HTTPCACHE_PURGE_TYPE varnish; 107 | fastcgi_param HTTPCACHE_PURGE_SERVER 'http://varnish:80'; 108 | fastcgi_param TRUSTED_PROXIES "127.0.0.1,localhost,172.0.0.0/8,varnish,192.168.0.0/16"; 109 | } 110 | } 111 | include ez_params.d/ez_server_params; 112 | } 113 | -------------------------------------------------------------------------------- /payload/dev/nginx/nginx_v2.conf: -------------------------------------------------------------------------------- 1 | # GZIP 2 | gzip on; 3 | gzip_disable "msie6"; 4 | gzip_proxied any; 5 | gzip_comp_level 6; 6 | gzip_buffers 16 8k; 7 | gzip_http_version 1.1; 8 | gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript; 9 | 10 | # DEV MODE 11 | server { 12 | listen 80; 13 | server_name _; 14 | # Project Root = project-path-container = /var/www/html/project 15 | # Would be great to get that from ENV var PROJECTMAPPINGFOLDER 16 | root "/var/www/html/project/ezplatform/web"; 17 | 18 | # FOR DFS 19 | # include ez_params.d/ez_rewrite_dfsimage_params; 20 | 21 | # ez rewrite rules 22 | include ez_params.d/ez_rewrite_params; 23 | 24 | # upload max size 25 | client_max_body_size 40M; 26 | 27 | # FPM fastcgi_read_timeout 28 | fastcgi_read_timeout 30; 29 | 30 | location / { 31 | location ~ ^/app\.php(/|$) { 32 | include ez_params.d/ez_fastcgi_params; 33 | fastcgi_pass engine:9000; 34 | fastcgi_param SYMFONY_ENV dev; 35 | fastcgi_param RUNNING_ENV DOCKER; 36 | } 37 | } 38 | include ez_params.d/ez_server_params; 39 | } 40 | 41 | # PROD MODE - Symfony Reverse Proxy 42 | server { 43 | listen 81; 44 | server_name _; 45 | # Project Root = project-path-container = /var/www/html/project 46 | # Would be great to get that from ENV var PROJECTMAPPINGFOLDER 47 | root "/var/www/html/project/ezplatform/web"; 48 | 49 | include ez_params.d/ez_prod_rewrite_params; 50 | 51 | # FOR DFS 52 | # include ez_params.d/ez_rewrite_dfsimage_params; 53 | 54 | # ez rewrite rules 55 | include ez_params.d/ez_rewrite_params; 56 | 57 | # upload max size 58 | client_max_body_size 40M; 59 | 60 | # FPM fastcgi_read_timeout 61 | fastcgi_read_timeout 30; 62 | 63 | location / { 64 | location ~ ^/app\.php(/|$) { 65 | include ez_params.d/ez_fastcgi_params; 66 | 67 | fastcgi_pass engine:9000; 68 | fastcgi_param SYMFONY_ENV prod; 69 | fastcgi_param RUNNING_ENV DOCKER; 70 | } 71 | } 72 | include ez_params.d/ez_server_params; 73 | } 74 | 75 | 76 | # PROD MODE - Varnish 77 | server { 78 | listen 82; 79 | server_name _; 80 | # Project Root = project-path-container = /var/www/html/project 81 | # Would be great to get that from ENV var PROJECTMAPPINGFOLDER 82 | root "/var/www/html/project/ezplatform/web"; 83 | 84 | include ez_params.d/ez_prod_rewrite_params; 85 | 86 | # FOR DFS 87 | # include ez_params.d/ez_rewrite_dfsimage_params; 88 | 89 | # ez rewrite rules 90 | include ez_params.d/ez_rewrite_params; 91 | 92 | # upload max size 93 | client_max_body_size 40M; 94 | 95 | # FPM fastcgi_read_timeout 96 | fastcgi_read_timeout 30; 97 | 98 | location / { 99 | location ~ ^/app\.php(/|$) { 100 | include ez_params.d/ez_fastcgi_params; 101 | 102 | fastcgi_pass engine:9000; 103 | fastcgi_param SYMFONY_ENV prod; 104 | fastcgi_param RUNNING_ENV DOCKER; 105 | fastcgi_param SYMFONY_HTTP_CACHE 0; 106 | fastcgi_param HTTPCACHE_PURGE_TYPE http; 107 | fastcgi_param HTTPCACHE_PURGE_SERVER 'http://varnish:80'; 108 | fastcgi_param SYMFONY_TRUSTED_PROXIES "127.0.0.1,localhost,172.0.0.0/8,varnish"; 109 | } 110 | } 111 | include ez_params.d/ez_server_params; 112 | } 113 | -------------------------------------------------------------------------------- /payload/dev/solr/entrypoint.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Check if missing template folder 4 | DESTINATION_EZ="/ezsolr/server/ez" 5 | DESTINATION_TEMPLATE="${DESTINATION_EZ}/template" 6 | if [ ! -d ${DESTINATION_TEMPLATE} ]; then 7 | cd $PROJECTMAPPINGFOLDER/ezplatform 8 | mkdir -p ${DESTINATION_TEMPLATE} 9 | cp -R vendor/ezsystems/ezplatform-solr-search-engine/lib/Resources/config/solr/* ${DESTINATION_TEMPLATE} 10 | fi 11 | 12 | # Check for solr config folder (changes btw 6 and 7) 13 | SOURCE_SOLR="/opt/solr/server/solr/configsets/_default/" 14 | if [ ! -d ${SOURCE_SOLR} ]; then 15 | SOURCE_SOLR="/opt/solr/server/solr/configsets/basic_configs/" 16 | fi 17 | 18 | mkdir -p ${DESTINATION_EZ} 19 | if [ ! -f ${DESTINATION_EZ}/solr.xml ]; then 20 | cp /opt/solr/server/solr/solr.xml ${DESTINATION_EZ} 21 | cp ${SOURCE_SOLR}/conf/{currency.xml,solrconfig.xml,stopwords.txt,synonyms.txt,elevate.xml} ${DESTINATION_TEMPLATE} 22 | sed -i.bak '//d' ${DESTINATION_TEMPLATE}/solrconfig.xml 23 | sed -i -e 's/${solr.autoSoftCommit.maxTime:-1}<\/maxTime>/${solr.autoSoftCommit.maxTime:20}<\/maxTime>/g' ${DESTINATION_TEMPLATE}/solrconfig.xml 24 | sed -i -e 's/${solr.data.dir:}<\/dataDir>/\/opt\/solr\/data\/${solr.core.name}<\/dataDir>/g' ${DESTINATION_TEMPLATE}/solrconfig.xml 25 | fi 26 | 27 | SOLR_CORES=${SOLR_CORES:-collection1} 28 | CREATE_CORES=false 29 | 30 | for core in $SOLR_CORES 31 | do 32 | if [ ! -d ${DESTINATION_EZ}/${core} ]; then 33 | CREATE_CORES=true 34 | echo "Found missing core: ${core}" 35 | fi 36 | done 37 | 38 | if [ "$CREATE_CORES" = true ]; then 39 | touch ${DESTINATION_EZ}/solr.creating.cores 40 | echo "Start solr on background to create missing cores" 41 | /opt/solr/bin/solr -s ${DESTINATION_EZ} 42 | 43 | for core in $SOLR_CORES 44 | do 45 | if [ ! -d ${DESTINATION_EZ}/${core} ]; then 46 | /opt/solr/bin/solr create_core -c ${core} -d ${DESTINATION_TEMPLATE} 47 | echo "Core ${core} created." 48 | fi 49 | done 50 | echo "Stop background solr" 51 | /opt/solr/bin/solr stop 52 | rm ${DESTINATION_EZ}/solr.creating.cores 53 | fi 54 | 55 | /opt/solr/bin/solr -s ${DESTINATION_EZ} -f 56 | -------------------------------------------------------------------------------- /payload/recipes/composer_install.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | cd $PROJECTMAPPINGFOLDER 4 | 5 | # As we are doing build and up we might run here before the end of the entrypoint 6 | while true ; do 7 | if [ -d /var/www/.composer ]; then 8 | if ls -la /var/www/.composer | grep -q "www-data"; then 9 | break 10 | fi 11 | fi 12 | echo -n "." 13 | sleep 2 14 | done 15 | echo "" 16 | 17 | if [ ! -f /usr/local/bin/composer ]; 18 | then 19 | echo "WARNING: you don't have the last image of the PHP ENGINE" 20 | echo "TO FIX RUN: ~/ez docker:update" 21 | fi 22 | 23 | /usr/local/bin/composer self-update > /dev/null 2>&1 24 | 25 | sleep 2 26 | -------------------------------------------------------------------------------- /payload/recipes/create_dump.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | cd $PROJECTMAPPINGFOLDER 4 | 5 | 6 | mkdir -p data 7 | 8 | DUMP_DIR="$(pwd)/data" 9 | if [ "$1" != "" ] && [ -d "$1" ]; then 10 | if [[ "$1" =~ ^/ ]]; then 11 | DUMP_DIR="$1" 12 | fi 13 | fi 14 | 15 | DATABASE_PREFIXES=${DATABASE_PREFIXES:-DATABASE} 16 | 17 | for prefix in $DATABASE_PREFIXES 18 | do 19 | DATABASE_NAME_VAR=${prefix}_NAME 20 | DATABASE_HOST_VAR=${prefix}_HOST 21 | DATABASE_USER_VAR=${prefix}_USER 22 | DATABASE_PASSWORD_VAR=${prefix}_PASSWORD 23 | 24 | # Wait for the DB 25 | while ! mysqladmin ping -h"${!DATABASE_HOST_VAR}" -u"${!DATABASE_USER_VAR}" -p"${!DATABASE_PASSWORD_VAR}" --silent; do 26 | echo -n "." 27 | sleep 1 28 | done 29 | echo "" 30 | 31 | DB_FILE_NAME="${!DATABASE_NAME_VAR}" 32 | 33 | MYSQLDUMP="mysqldump -h${!DATABASE_HOST_VAR} -u${!DATABASE_USER_VAR} -p${!DATABASE_PASSWORD_VAR}" 34 | 35 | echo "Dumping ${!DATABASE_NAME_VAR} database." 36 | $MYSQLDUMP ${!DATABASE_NAME_VAR} > $DUMP_DIR/$DB_FILE_NAME.sql 37 | gzip -f $DUMP_DIR/$DB_FILE_NAME.sql 38 | echo "${!DATABASE_NAME_VAR} database dumped." 39 | done 40 | 41 | 42 | STORAGE_FILE_NAME="storage" 43 | 44 | if [ "$2" != "" ]; then 45 | STORAGE_FILE_NAME="$2_storage" 46 | fi 47 | 48 | if [ -d $PROJECTMAPPINGFOLDER/ezplatform/web/var ]; then 49 | cd $PROJECTMAPPINGFOLDER/ezplatform/web 50 | tar czvf $DUMP_DIR/$STORAGE_FILE_NAME.tar.gz var/ 51 | cd - 52 | echo "Storage dumped from web/." 53 | fi 54 | 55 | if [ -d $PROJECTMAPPINGFOLDER/ezplatform/public/var ]; then 56 | cd $PROJECTMAPPINGFOLDER/ezplatform/public 57 | tar czvf $DUMP_DIR/$STORAGE_FILE_NAME.tar.gz var/ 58 | cd - 59 | echo "Storage dumped from public/." 60 | fi 61 | -------------------------------------------------------------------------------- /payload/recipes/ez_create.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | cd $PROJECTMAPPINGFOLDER 4 | 5 | PHP="php" 6 | COMPOSER="$PHP -d memory_limit=-1 /usr/local/bin/composer" 7 | REPO=$1 8 | VERSION=$2 9 | 10 | DATABASE_PREFIXES=${DATABASE_PREFIXES:-DATABASE} 11 | for prefix in $DATABASE_PREFIXES 12 | do 13 | DATABASE_NAME_VAR=${prefix}_NAME 14 | DATABASE_HOST_VAR=${prefix}_HOST 15 | DATABASE_USER_VAR=${prefix}_USER 16 | DATABASE_PASSWORD_VAR=${prefix}_PASSWORD 17 | 18 | # Wait for the DB 19 | while ! mysqladmin ping -h"${!DATABASE_HOST_VAR}" -u"${!DATABASE_USER_VAR}" -p"${!DATABASE_PASSWORD_VAR}" --silent; do 20 | echo -n "." 21 | sleep 1 22 | done 23 | echo "" 24 | 25 | mysql -h"${!DATABASE_HOST_VAR}" -u"${!DATABASE_USER_VAR}" -p"${!DATABASE_PASSWORD_VAR}" -e "CREATE DATABASE ${!DATABASE_NAME_VAR}" 26 | done 27 | 28 | if [ ! -d ezplatform ]; then 29 | echo "Not managed yet." 30 | exit 31 | fi 32 | 33 | CONSOLE="bin/console" 34 | if [ -f ezplatform/app/console ]; then 35 | CONSOLE="app/console" 36 | fi 37 | 38 | # Install 39 | cd ezplatform 40 | 41 | $COMPOSER install --no-interaction 42 | 43 | echo "Installation OK" 44 | 45 | -------------------------------------------------------------------------------- /payload/recipes/ez_install.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | cd $PROJECTMAPPINGFOLDER 4 | 5 | PHP="php" 6 | COMPOSER="$PHP -d memory_limit=-1 /usr/local/bin/composer" 7 | REPO=$1 8 | VERSION=$2 9 | INIT_DATA=$3 10 | 11 | DATABASE_PREFIXES=${DATABASE_PREFIXES:-DATABASE} 12 | for prefix in $DATABASE_PREFIXES 13 | do 14 | DATABASE_NAME_VAR=${prefix}_NAME 15 | DATABASE_HOST_VAR=${prefix}_HOST 16 | DATABASE_USER_VAR=${prefix}_USER 17 | DATABASE_PASSWORD_VAR=${prefix}_PASSWORD 18 | 19 | # Wait for the DB 20 | while ! mysqladmin ping -h"${!DATABASE_HOST_VAR}" -u"${!DATABASE_USER_VAR}" -p"${!DATABASE_PASSWORD_VAR}" --silent; do 21 | echo -n "." 22 | sleep 1 23 | done 24 | echo "" 25 | 26 | mysql -h"${!DATABASE_HOST_VAR}" -u"${!DATABASE_USER_VAR}" -p"${!DATABASE_PASSWORD_VAR}" -e "CREATE DATABASE ${!DATABASE_NAME_VAR}" 27 | done 28 | 29 | echo "Installation eZ Platform ($REPO:$VERSION:$INIT_DATA) in the container" 30 | 31 | # Install 32 | $COMPOSER create-project --no-interaction $REPO ezplatform $VERSION 33 | cd ezplatform 34 | 35 | MAJOR_VERSION=`echo $VERSION | cut -c 1-2` 36 | 37 | # Do some cleaning 38 | ## Folder 39 | rm -rf bin/.ci bin/.travis 40 | 41 | CONSOLE="bin/console" 42 | if [ -f app/console ]; then 43 | CONSOLE="app/console" 44 | fi 45 | 46 | 47 | # Prefer install via composer alias (added in v2.2, required for eZ Commerce) 48 | if $COMPOSER run-script -l | grep -q " $INIT_DATA "; then 49 | $COMPOSER run-script $INIT_DATA 50 | else 51 | $PHP $CONSOLE ezplatform:install $INIT_DATA 52 | fi 53 | 54 | 55 | 56 | echo "Installation OK" 57 | 58 | -------------------------------------------------------------------------------- /payload/recipes/ez_install_solr.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | PROVISIONING=$1 4 | ACTION=$2 5 | 6 | DESTINATION_EZ="/ezsolr/server/ez" 7 | DESTINATION_TEMPLATE="$DESTINATION_EZ/template" 8 | PHP="php" 9 | 10 | if [ $ACTION == "COMPOSER_INSTALL" ]; then 11 | # it is run on the engine 12 | cd $PROJECTMAPPINGFOLDER/ezplatform 13 | mkdir -p $DESTINATION_TEMPLATE 14 | cp -R vendor/ezsystems/ezplatform-solr-search-engine/lib/Resources/config/solr/* $DESTINATION_TEMPLATE 15 | # simplest way to allow solr to add the conf here... from its own container 16 | # We could do better by extending the Dockerfile and build.. but it is also less "generic" 17 | chmod -R 777 $DESTINATION_EZ 18 | fi 19 | 20 | if [ $ACTION == "INDEX" ]; then 21 | # it is run on the engine 22 | until wget -q -O - http://solr:8983 | grep -q -i solr; do 23 | echo -n "." 24 | sleep 2 25 | done 26 | # wait cores 27 | sleep 15 28 | echo "Solr is running" 29 | cd $PROJECTMAPPINGFOLDER/ezplatform 30 | CONSOLE="bin/console" 31 | if [ -f app/console ]; then 32 | CONSOLE="app/console" 33 | fi 34 | $PHP $CONSOLE --env=prod ezplatform:reindex 35 | fi 36 | 37 | if [ $ACTION == "CREATE_CORE" ]; then 38 | # it is run on the solr 39 | until wget -q -O - http://localhost:8983 | grep -q -i solr; do 40 | echo -n "." 41 | sleep 2 42 | done 43 | # wait until create cores from solr entry point is done 44 | until [ ! -f ${DESTINATION_EZ}/solr.creating.cores ]; do 45 | echo -n "c" 46 | sleep 2 47 | done 48 | 49 | echo "Solr is running" 50 | 51 | SOLR_CORES=${SOLR_CORES:-collection1} 52 | for core in $SOLR_CORES 53 | do 54 | if [ ! -d ${DESTINATION_EZ}/${core} ]; then 55 | /opt/solr/bin/solr create_core -c ${core} -d $DESTINATION_TEMPLATE 56 | echo "Core ${core} created." 57 | fi 58 | done 59 | 60 | fi 61 | 62 | -------------------------------------------------------------------------------- /payload/recipes/ibexa_install.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | cd $PROJECTMAPPINGFOLDER 4 | 5 | PHP="php" 6 | COMPOSER="$PHP -d memory_limit=-1 /usr/local/bin/composer" 7 | REPO=$1 8 | VERSION=$2 9 | INIT_DATA=$3 10 | DATABASE_PREFIXES=${DATABASE_PREFIXES:-DATABASE} 11 | CONSOLE="bin/console" 12 | 13 | for prefix in $DATABASE_PREFIXES 14 | do 15 | DATABASE_NAME_VAR=${prefix}_NAME 16 | DATABASE_HOST_VAR=${prefix}_HOST 17 | DATABASE_USER_VAR=${prefix}_USER 18 | DATABASE_PASSWORD_VAR=${prefix}_PASSWORD 19 | 20 | # Wait for the DB 21 | while ! mysqladmin ping -h"${!DATABASE_HOST_VAR}" -u"${!DATABASE_USER_VAR}" -p"${!DATABASE_PASSWORD_VAR}" --silent; do 22 | echo -n "." 23 | sleep 1 24 | done 25 | echo "" 26 | 27 | mysql -h"${!DATABASE_HOST_VAR}" -u"${!DATABASE_USER_VAR}" -p"${!DATABASE_PASSWORD_VAR}" -e "CREATE DATABASE ${!DATABASE_NAME_VAR}" 28 | done 29 | 30 | echo "Installation Ibexa ($REPO - $VERSION) in the container" 31 | 32 | # Install ibexa/website-skeleton 33 | echo "Install ibexa/website-skeleton" 34 | $COMPOSER create-project --no-interaction $REPO-skeleton ezplatform $VERSION 35 | cd ezplatform 36 | # Copy nginx conf 37 | echo "Getting the NGINX config" 38 | wget https://github.com/ibexa/docker/archive/main.zip 39 | unzip main.zip 40 | mkdir -p doc 41 | cp -r docker-main/templates/nginx doc/ 42 | rm -rf docker-main 43 | rm main.zip 44 | 45 | # Add .env.local to set database configuration 46 | echo "Add .env.local to set database configuration" 47 | echo "DATABASE_URL=\${DATABASE_PLATFORM}://\${DATABASE_USER}:\${DATABASE_PASSWORD}@\${DATABASE_HOST}:\${DATABASE_PORT}/\${DATABASE_NAME}?serverVersion=\${DATABASE_VERSION}" > ".env.local" 48 | 49 | # Test the package version 50 | if [ "$REPO" != "ibexa/oss" ]; then 51 | echo "configure auth updates.ibexa.co" 52 | $COMPOSER config repositories.ibexa composer https://updates.ibexa.co 53 | fi 54 | 55 | MAJOR_VERSION=`echo $VERSION | cut -c 1-2` 56 | 57 | # Do some cleaning 58 | ## Folder 59 | rm -rf bin/.ci bin/.travis 60 | 61 | echo "Installation Ibexa $REPO OK" 62 | 63 | # Prefer install via composer alias (added in v2.2, required for eZ Commerce) 64 | if $COMPOSER run-script -l | grep -q " $INIT_DATA "; then 65 | $COMPOSER run-script $INIT_DATA 66 | else 67 | echo "php bin/console ibexa:install " 68 | $PHP $CONSOLE ibexa:install $INIT_DATA 69 | fi 70 | echo "php bin/console ibexa:graphql:generate-schema" 71 | $PHP $CONSOLE ibexa:graphql:generate-schema 72 | echo "composer run post-update-cmd" 73 | $COMPOSER run-script post-install-cmd 74 | 75 | echo "Database init OK" 76 | -------------------------------------------------------------------------------- /payload/recipes/import_dump.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | cd $PROJECTMAPPINGFOLDER 4 | 5 | DUMP_DIR="$(pwd)/data" 6 | if [ "$1" != "" ] && [ -d "$1" ]; then 7 | if [[ "$1" =~ ^/ ]]; then 8 | DUMP_DIR="$1" 9 | fi 10 | fi 11 | 12 | DATABASE_PREFIXES=${DATABASE_PREFIXES:-DATABASE} 13 | 14 | for prefix in $DATABASE_PREFIXES 15 | do 16 | DATABASE_NAME_VAR=${prefix}_NAME 17 | DATABASE_HOST_VAR=${prefix}_HOST 18 | DATABASE_USER_VAR=${prefix}_USER 19 | DATABASE_PASSWORD_VAR=${prefix}_PASSWORD 20 | 21 | # Wait for the DB 22 | while ! mysqladmin ping -h"${!DATABASE_HOST_VAR}" -u"${!DATABASE_USER_VAR}" -p"${!DATABASE_PASSWORD_VAR}" --silent; do 23 | echo -n "." 24 | sleep 1 25 | done 26 | echo "" 27 | 28 | DB_FILE_NAME="${!DATABASE_NAME_VAR}" 29 | DB_FILE_PATH="$DUMP_DIR/$DB_FILE_NAME.sql" 30 | 31 | MYSQL="mysql -h${!DATABASE_HOST_VAR} -u${!DATABASE_USER_VAR} -p${!DATABASE_PASSWORD_VAR}" 32 | 33 | echo "Importing ${!DATABASE_NAME_VAR} database." 34 | zcat $DB_FILE_PATH | $MYSQL ${!DATABASE_NAME_VAR} 35 | echo "${!DATABASE_NAME_VAR} database imported." 36 | done 37 | 38 | 39 | STORAGE_FILE_NAME="storage" 40 | if [ "$2" != "" ]; then 41 | STORAGE_FILE_NAME="$2_storage" 42 | fi 43 | 44 | STORAGE_FILE_PATH="$DUMP_DIR/$STORAGE_FILE_NAME.tar.gz" 45 | 46 | if [ ! -d ezplatform ]; then 47 | echo "Not managed yet." 48 | exit 49 | fi 50 | 51 | if [ -f $STORAGE_FILE_PATH ]; then 52 | if [ -d ezplatform/web ]; then 53 | if [ -d "ezplatform/web/var" ]; then 54 | rm -rf ezplatform/web/var 55 | fi 56 | tar xvzf $STORAGE_FILE_PATH -C ezplatform/web/ 57 | echo "Storage imported to web/." 58 | fi 59 | if [ -d ezplatform/public ]; then 60 | if [ -d "ezplatform/public/var" ]; then 61 | rm -rf ezplatform/public/var 62 | fi 63 | tar xvzf $STORAGE_FILE_PATH -C ezplatform/public/ 64 | echo "Storage imported to public/." 65 | fi 66 | fi 67 | -------------------------------------------------------------------------------- /scripts/buildbox.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | BASEDIR=$(dirname $0) 3 | PHP="env php " 4 | source ${BASEDIR}/functions 5 | PROJECTDIR="${BASEDIR}/../" 6 | 7 | cd ${PROJECTDIR} 8 | 9 | echoTitle "******** Build it! ********" 10 | ulimit -Sn 4096 11 | 12 | if [ ! -f composer.phar ]; then 13 | echoInfo "Install composer.phar before..." 14 | curl -s http://getcomposer.org/installer | $PHP 15 | echoAction "Building now..." 16 | fi 17 | if [ ! -f box.phar ]; then 18 | echoInfo "Install box.phar before..." 19 | curl -LSs https://box-project.github.io/box2/installer.php | $PHP 20 | echoAction "Building now..." 21 | fi 22 | 23 | $PHP composer.phar install --no-dev > /dev/null 2>&1 24 | $PHP -d "phar.readonly=false" box.phar build -vvv 25 | $PHP composer.phar install > /dev/null 2>&1 26 | 27 | echoSuccess "Done." 28 | exit 0; 29 | -------------------------------------------------------------------------------- /scripts/codechecker.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | BASEDIR=$(dirname $0) 4 | PHP="env php" 5 | 6 | source ${BASEDIR}/functions 7 | PROJECTDIR="${BASEDIR}/../" 8 | 9 | if [ -z "$1" ]; then 10 | SRC="src/" 11 | else 12 | SRC="$1" 13 | fi 14 | 15 | cd ${PROJECTDIR} 16 | 17 | echoTitle "******** Mess Detector ********" 18 | $PHP ./vendor/bin/phpmd $SRC text .cs/md_ruleset.xml 19 | $PHP ./vendor/bin/phpmd tests/Tests text .cs/md_ruleset.xml 20 | 21 | echoTitle "******** CodeFixer ************" 22 | $PHP ./vendor/bin/php-cs-fixer fix --config=.cs/.php_cs.php 23 | 24 | echoTitle "******** CodeSniffer **********" 25 | $PHP ./vendor/bin/phpcs --standard=.cs/cs_ruleset.xml --extensions=php $SRC 26 | $PHP ./vendor/bin/phpcs --standard=.cs/cs_ruleset.xml --extensions=php tests/Tests 27 | 28 | echoSuccess "Done." 29 | exit 0; 30 | -------------------------------------------------------------------------------- /scripts/functions: -------------------------------------------------------------------------------- 1 | #-- Vars 2 | RESTORE=$(echo -en '\033[0m') 3 | RED=$(echo -en '\033[00;31m') 4 | GREEN=$(echo -en '\033[00;32m') 5 | YELLOW=$(echo -en '\033[00;33m') 6 | BLUE=$(echo -en '\033[00;34m') 7 | MAGENTA=$(echo -en '\033[00;35m') 8 | PURPLE=$(echo -en '\033[00;35m') 9 | CYAN=$(echo -en '\033[00;36m') 10 | LIGHTGRAY=$(echo -en '\033[00;37m') 11 | LRED=$(echo -en '\033[01;31m') 12 | LGREEN=$(echo -en '\033[01;32m') 13 | LYELLOW=$(echo -en '\033[01;33m') 14 | LBLUE=$(echo -en '\033[01;34m') 15 | LMAGENTA=$(echo -en '\033[01;35m') 16 | LPURPLE=$(echo -en '\033[01;35m') 17 | LCYAN=$(echo -en '\033[01;36m') 18 | WHITE=$(echo -en '\033[01;37m') 19 | BOLD=$(echo -en '\033[1m') 20 | 21 | 22 | #-- Functions 23 | 24 | f_startColor () 25 | { 26 | echo -en "$1" 27 | } 28 | 29 | f_resetColor () 30 | { 31 | echo -en "${RESTORE}" 32 | } 33 | 34 | echoInfo () 35 | { 36 | echo "${CYAN}[${RESTORE}${BOLD}*${CYAN}]${RESTORE} $1" 37 | } 38 | 39 | echoAction () 40 | { 41 | echo "${RED}[${LBLUE}ACTION${RESTORE}${RED}]${RESTORE} $1 ${RESTORE}" 42 | } 43 | 44 | echoSuccess () 45 | { 46 | echo "${LRED}[${BOLD}${LGREEN}OK${RESTORE}${LRED}]${RESTORE} $1 ${RESTORE}" 47 | } 48 | 49 | echoNothing () 50 | { 51 | echo "${LRED}[${BOLD}${LGREEN}-${RESTORE}${LRED}]${RESTORE} $1 ${RESTORE}" 52 | } 53 | 54 | echoTitle () 55 | { 56 | echo "${BOLD}${LPURPLE}====${RESTORE} ${LYELLOW}$1${RESTORE} ${BOLD}${LPURPLE}====${RESTORE}" 57 | } 58 | 59 | echoHelp () 60 | { 61 | echo "${BOLD}$1${RESTORE}: ${GREEN}$2${RESTORE}" 62 | } 63 | -------------------------------------------------------------------------------- /scripts/pumltoimages.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | BASEDIR=$(dirname $0) 4 | PUML="java -jar ${BASEDIR}/../plantuml.jar" 5 | 6 | $PUML -o images/puml docs/*.puml 7 | -------------------------------------------------------------------------------- /scripts/runtests.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | BASEDIR=$(dirname $0) 4 | PHP="env php " 5 | source ${BASEDIR}/functions 6 | PROJECTDIR="${BASEDIR}/../" 7 | 8 | cd ${PROJECTDIR} 9 | 10 | if [ $# -eq 0 ] || [ "$1" == "unit" ]; then 11 | echoTitle "PHPUNIT Tests" 12 | $PHP ./vendor/bin/phpunit -c tests/ --exclude-group behat 13 | fi 14 | 15 | if [ $# -eq 0 ]; then 16 | echo "" 17 | echo "***************" 18 | echo "" 19 | fi 20 | 21 | if [ $# -eq 0 ] || [ "$1" == "behat" ]; then 22 | echoTitle "BEHAT Test" 23 | $PHP ./vendor/bin/behat -c tests/behat.yml 24 | fi 25 | 26 | echoSuccess "Done." 27 | exit 0; 28 | -------------------------------------------------------------------------------- /scripts/travis_deploy.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Unpack secrets; -C ensures they unpack *in* the .travis directory 4 | tar xvf .travis/secrets.tar -C .travis 5 | 6 | # Setup SSH agent: 7 | eval "$(ssh-agent -s)" #start the ssh agent 8 | chmod 600 .travis/build-key.pem 9 | ssh-add .travis/build-key.pem 10 | 11 | # Setup git defaults: 12 | git config --global user.email "github-ezlaunchpad@ez.no" 13 | git config --global user.name "eZ Launchpad Github Bot" 14 | 15 | # Add SSH-based remote to GitHub repo: 16 | git remote add deploy git@github.com:ezsystems/launchpad.git 17 | git fetch deploy 18 | git checkout master 19 | git status 20 | 21 | # Get box and build PHAR 22 | curl -LSs https://box-project.github.io/box2/installer.php | php 23 | chmod 755 box.phar 24 | 25 | composer install --no-dev 26 | 27 | # Build the box 28 | ./box.phar build -vv 29 | 30 | # Generate the PHAR 31 | sha1sum ez.phar > docs/ez.phar.version 32 | mv ez.phar docs/ez.phar 33 | git add docs/ez.phar docs/ez.phar.version 34 | 35 | # Commit and push: 36 | DATED_SUFFIX=`date +%Y-%m-%d-%H-%M-%S` 37 | git commit -m "[skip ci] Deployment new eZ Launchpad on $DATED_SUFFIX" 38 | git push deploy master 39 | -------------------------------------------------------------------------------- /src/Command/Docker/Build.php: -------------------------------------------------------------------------------- 1 | setName('docker:build')->setDescription('Build all the services (or just one).'); 23 | $this->addArgument('service', InputArgument::OPTIONAL, 'Service to build', ''); 24 | $this->setAliases(['build']); 25 | } 26 | 27 | protected function execute(InputInterface $input, OutputInterface $output): int 28 | { 29 | $this->dockerClient->build([], $input->getArgument('service')); 30 | $this->taskExecutor->composerInstall(); 31 | 32 | return DockerCommand::SUCCESS; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Command/Docker/Clean.php: -------------------------------------------------------------------------------- 1 | setName('docker:clean')->setDescription('Clean all the services.'); 22 | $this->setAliases(['docker:down', 'clean', 'down']); 23 | } 24 | 25 | protected function execute(InputInterface $input, OutputInterface $output): int 26 | { 27 | $this->dockerClient->down(['-v', '--remove-orphans']); 28 | 29 | return DockerCommand::SUCCESS; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Command/Docker/ComposerRun.php: -------------------------------------------------------------------------------- 1 | setName('docker:comprun')->setDescription('Run Composer command in the engine.'); 23 | $this->setAliases(['comprun']); 24 | $this->addArgument( 25 | 'compcommand', 26 | InputArgument::IS_ARRAY, 27 | 'Composer Command to run in. Use "" to pass options.' 28 | ); 29 | } 30 | 31 | protected function execute(InputInterface $input, OutputInterface $output): int 32 | { 33 | $allArguments = $input->getArgument('compcommand'); 34 | $options = ''; 35 | $this->taskExecutor->runComposerCommand(implode(' ', $allArguments)." {$options}"); 36 | 37 | return DockerCommand::SUCCESS; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Command/Docker/Create.php: -------------------------------------------------------------------------------- 1 | projectStatusDumper = $projectStatusDumper; 28 | } 29 | 30 | protected function configure(): void 31 | { 32 | parent::configure(); 33 | $this->setName('docker:create')->setDescription('Create all the services.'); 34 | $this->setAliases(['create']); 35 | } 36 | 37 | protected function initialize(InputInterface $input, OutputInterface $output): void 38 | { 39 | parent::initialize($input, $output); 40 | $this->projectStatusDumper->setDockerClient($this->dockerClient); 41 | $this->projectStatusDumper->setIo($this->io); 42 | } 43 | 44 | protected function execute(InputInterface $input, OutputInterface $output): int 45 | { 46 | $this->dockerClient->build(['--no-cache']); 47 | $this->dockerClient->up(['-d']); 48 | 49 | $this->taskExecutor->composerInstall(); 50 | $this->taskExecutor->eZCreate(); 51 | $this->taskExecutor->importData(); 52 | 53 | // if solr run the index 54 | $compose = $this->projectConfiguration->getDockerCompose(); 55 | if ($compose->hasService('solr')) { 56 | $this->taskExecutor->createCore(); 57 | $this->taskExecutor->indexSolr(); 58 | } 59 | 60 | $this->projectStatusDumper->dump('ncsi'); 61 | 62 | return DockerCommand::SUCCESS; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Command/Docker/DumpData.php: -------------------------------------------------------------------------------- 1 | setName('docker:dumpdata')->setDescription('Dump Database and Storage.'); 22 | $this->setAliases(['dumpdata']); 23 | } 24 | 25 | protected function execute(InputInterface $input, OutputInterface $output): int 26 | { 27 | $this->taskExecutor->dumpData(); 28 | 29 | return DockerCommand::SUCCESS; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Command/Docker/Enter.php: -------------------------------------------------------------------------------- 1 | setName('docker:enter')->setDescription('Enter in a container.'); 24 | $this->addArgument('service', InputArgument::OPTIONAL, 'Service to enter in', 'engine'); 25 | $this->addOption('user', 'u', InputOption::VALUE_REQUIRED, 'User with who to enter in', 'www-data'); 26 | $this->addArgument('shell', InputArgument::OPTIONAL, 'Command to enter in', '/bin/bash'); 27 | $this->setAliases(['enter', 'docker:exec', 'exec']); 28 | } 29 | 30 | protected function execute(InputInterface $input, OutputInterface $output): int 31 | { 32 | $this->dockerClient->exec( 33 | $input->getArgument('shell'), 34 | [ 35 | '--user', $input->getOption('user'), 36 | ], 37 | $input->getArgument('service') 38 | ); 39 | 40 | return DockerCommand::SUCCESS; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Command/Docker/ImportData.php: -------------------------------------------------------------------------------- 1 | setName('docker:importdata')->setDescription('Import Database and Storage.'); 22 | $this->setAliases(['importdata']); 23 | } 24 | 25 | protected function execute(InputInterface $input, OutputInterface $output): int 26 | { 27 | $this->taskExecutor->importData(); 28 | 29 | return DockerCommand::SUCCESS; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Command/Docker/InitializeSkeleton.php: -------------------------------------------------------------------------------- 1 | setName('docker:initialize:skeleton')->setDescription( 24 | 'Initialize without all of eZ. (REALLY experimental)' 25 | ); 26 | $this->setAliases(['docker:init:skeleton', 'init-skeleton']); 27 | $this->setHidden(true); 28 | } 29 | 30 | protected function innerInitialize( 31 | Docker $dockerClient, 32 | DockerCompose $compose, 33 | $composeFilePath, 34 | InputInterface $input 35 | ): void { 36 | $compose->cleanForInitializeSkeleton(); 37 | $compose->dump($composeFilePath); 38 | 39 | $fs = new Filesystem(); 40 | // Empty Nginx 41 | $nginxEmptyConf = <<dumpFile( 136 | "{$this->projectConfiguration->get('provisioning.folder_name')}/dev/nginx/nginx.conf", 137 | $nginxEmptyConf 138 | ); 139 | $fs->dumpFile( 140 | "{$this->projectConfiguration->get('provisioning.folder_name')}/dev/varnish/varnish.conf", 141 | $varnishEmptyConf 142 | ); 143 | 144 | $dockerClient->build(['--no-cache']); 145 | $dockerClient->up(['-d']); 146 | 147 | $executor = new TaskExecutor($dockerClient, $this->projectConfiguration, $this->requiredRecipes); 148 | $executor->composerInstall(); 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /src/Command/Docker/Logs.php: -------------------------------------------------------------------------------- 1 | setName('docker:logs')->setDescription('Display the logs.'); 23 | $this->addArgument('service', InputArgument::OPTIONAL, 'Service to log.', ''); 24 | $this->setAliases(['logs', 'log']); 25 | } 26 | 27 | protected function execute(InputInterface $input, OutputInterface $output): int 28 | { 29 | $this->dockerClient->logs(['-f', '--tail=100'], $input->getArgument('service')); 30 | 31 | return DockerCommand::SUCCESS; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Command/Docker/Restart.php: -------------------------------------------------------------------------------- 1 | setName('docker:restart')->setDescription('Restart all the services (or just one).'); 21 | $this->addArgument('service', InputArgument::OPTIONAL, 'Service to restart', ''); 22 | $this->setAliases(['restart']); 23 | } 24 | 25 | protected function execute(InputInterface $input, OutputInterface $output): int 26 | { 27 | $this->dockerClient->restart($input->getArgument('service')); 28 | 29 | return DockerCommand::SUCCESS; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Command/Docker/Start.php: -------------------------------------------------------------------------------- 1 | setName('docker:start')->setDescription('Start all the services (or just one).'); 23 | $this->addArgument('service', InputArgument::OPTIONAL, 'Service to start', ''); 24 | $this->setAliases(['start']); 25 | } 26 | 27 | protected function execute(InputInterface $input, OutputInterface $output): int 28 | { 29 | $this->dockerClient->start($input->getArgument('service')); 30 | 31 | return DockerCommand::SUCCESS; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Command/Docker/Status.php: -------------------------------------------------------------------------------- 1 | projectStatusDumper = $projectStatusDumper; 29 | } 30 | 31 | protected function configure(): void 32 | { 33 | parent::configure(); 34 | $this->setName('docker:status')->setDescription('Obtaining the project information.'); 35 | $this->setAliases(['docker:ps', 'docker:info', 'ps', 'info']); 36 | $this->addArgument( 37 | 'options', 38 | InputArgument::OPTIONAL, 39 | 'n: Docker Network, c: Docker Compose, s: Service Access', 40 | 'ncsz' 41 | ); 42 | } 43 | 44 | protected function initialize(InputInterface $input, OutputInterface $output): void 45 | { 46 | parent::initialize($input, $output); 47 | $this->projectStatusDumper->setDockerClient($this->dockerClient); 48 | $this->projectStatusDumper->setIo($this->io); 49 | } 50 | 51 | protected function execute(InputInterface $input, OutputInterface $output): int 52 | { 53 | $this->projectStatusDumper->dump($input->getArgument('options')); 54 | 55 | return DockerCommand::SUCCESS; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/Command/Docker/Stop.php: -------------------------------------------------------------------------------- 1 | setName('docker:stop')->setDescription('Stop all the services (or just one).'); 23 | $this->addArgument('service', InputArgument::OPTIONAL, 'Service to stop', ''); 24 | $this->setAliases(['stop']); 25 | } 26 | 27 | protected function execute(InputInterface $input, OutputInterface $output): int 28 | { 29 | $this->dockerClient->stop($input->getArgument('service')); 30 | 31 | return DockerCommand::SUCCESS; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Command/Docker/SymfonyRun.php: -------------------------------------------------------------------------------- 1 | setName('docker:sfrun')->setDescription('Run a Symfony command in the engine.'); 23 | $this->setAliases(['sfrun']); 24 | $this->addArgument('sfcommand', InputArgument::IS_ARRAY, 'Symfony Command to run in. Use "" to pass options.'); 25 | } 26 | 27 | protected function execute(InputInterface $input, OutputInterface $output): int 28 | { 29 | $allArguments = $input->getArgument('sfcommand'); 30 | $options = ''; 31 | $this->taskExecutor->runSymfomyCommand(implode(' ', $allArguments)." {$options}"); 32 | 33 | return DockerCommand::SUCCESS; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Command/Docker/Up.php: -------------------------------------------------------------------------------- 1 | setName('docker:up')->setDescription('Up all the services (or just one).'); 23 | $this->addArgument('service', InputArgument::OPTIONAL, 'Service to up', ''); 24 | $this->setAliases(['up']); 25 | } 26 | 27 | protected function execute(InputInterface $input, OutputInterface $output): int 28 | { 29 | $this->dockerClient->up(['-d'], $input->getArgument('service')); 30 | 31 | return DockerCommand::SUCCESS; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Command/Docker/Update.php: -------------------------------------------------------------------------------- 1 | setName('docker:update')->setDescription('Update to last images.'); 23 | $this->addArgument('service', InputArgument::OPTIONAL, 'Image service to update.', ''); 24 | } 25 | 26 | protected function execute(InputInterface $input, OutputInterface $output): int 27 | { 28 | $this->dockerClient->pull(['--ignore-pull-failures'], $input->getArgument('service')); 29 | $this->dockerClient->build([], $input->getArgument('service')); 30 | $this->dockerClient->up(['-d'], $input->getArgument('service')); 31 | $this->taskExecutor->composerInstall(); 32 | 33 | return DockerCommand::SUCCESS; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Command/Platformsh/Deploy.php: -------------------------------------------------------------------------------- 1 | setName('platformsh:deploy')->setDescription('Deploy with Platformsh integration.'); 23 | $this->setAliases(['psh:deploy']); 24 | } 25 | 26 | protected function execute(InputInterface $input, OutputInterface $output): int 27 | { 28 | $fs = new Filesystem(); 29 | $this->io->title($this->getDescription()); 30 | 31 | // add a test to see if folder exists or not 32 | if (!$fs->exists("{$this->projectPath}/.platform")) { 33 | $this->io->error('Your project is not Platformsh ready.'); 34 | $this->io->comment('Run ~/ez platformsh:setup to set up the integration.'); 35 | 36 | return Command::FAILURE; 37 | } 38 | 39 | $this->io->writeln( 40 | "There is no such thing with Platform.sh.\n". 41 | 'To deploy you just have to git push in the good'. 42 | " remote (usually: platform)\n". 43 | "Automatically Platform.sh will trigger the deployment.\n". 44 | "\nIf you just want to manage one unique git repository have a look: \n". 45 | "\tGithub Integration:\t https://docs.platform.sh/administration/integrations/github.html\n". 46 | "\tBitbucket Integration:\t https://docs.platform.sh/administration/integrations/bitbucket.html" 47 | ); 48 | 49 | return Command::SUCCESS; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/Command/Platformsh/Setup.php: -------------------------------------------------------------------------------- 1 | setName('platformsh:setup')->setDescription('Set up the Platformsh integration.'); 23 | $this->setAliases(['psh:setup']); 24 | } 25 | 26 | protected function postAction(): void 27 | { 28 | $this->io->writeln( 29 | 'You can also look at ~/ez platformsh:deploy.' 30 | ); 31 | } 32 | 33 | protected function execute(InputInterface $input, OutputInterface $output): int 34 | { 35 | $fs = new Filesystem(); 36 | $this->io->title($this->getDescription()); 37 | 38 | // add a test to see if folder exists or not 39 | if ($fs->exists("{$this->projectPath}/.platform")) { 40 | if (!$this->io->confirm('You already have a .platform folder, continue?')) { 41 | $this->postAction(); 42 | 43 | return DockerCommand::FAILURE; 44 | } 45 | } 46 | 47 | // Dump the project 48 | $this->taskExecutor->dumpData(); 49 | 50 | // move it to the top folder as required my Platform.sh 51 | $fs->rename("{$this->projectPath}/ezplatform/.platform", "{$this->projectPath}/.platform"); 52 | 53 | $this->io->writeln( 54 | "Your project is now set up with Platform.sh.\n". 55 | "You can run git status to see the changes\n". 56 | "Then you just have to \n". 57 | "\tgit add .\n". 58 | "\tgit commit -m \"Integration Platform.sh\"\n". 59 | "\tgit push platform {branchname}\n" 60 | ); 61 | 62 | $this->postAction(); 63 | 64 | return DockerCommand::SUCCESS; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/Command/SelfUpdate.php: -------------------------------------------------------------------------------- 1 | setName('self-update')->setDescription('Self Update'); 28 | } 29 | 30 | public function setParameters(array $parameters = []): void 31 | { 32 | $this->parameters = $parameters; 33 | } 34 | 35 | protected function execute(InputInterface $input, OutputInterface $output): int 36 | { 37 | /* @var Application $application */ 38 | $application = $this->getApplication(); 39 | $output->writeln($application->getLogo()); 40 | 41 | $releaseUrl = $this->parameters['release_url']; 42 | $releases = githubFetch($releaseUrl); 43 | if (null === $releases) { 44 | $this->io->comment('Cannot find new releases, please try later.'); 45 | 46 | return Command::FAILURE; 47 | } 48 | $release = $releases[0]; 49 | $currentVersion = normalizeVersion($application->getVersion()); 50 | $lastVersion = normalizeVersion($release->tag_name); 51 | if ($lastVersion <= $currentVersion) { 52 | $this->io->comment('No update is required! You have the last version!'); 53 | 54 | return Command::FAILURE; 55 | } 56 | 57 | $localPharFile = realpath($_SERVER['argv'][0]) ?: $_SERVER['argv'][0]; 58 | $localPharDir = \dirname($localPharFile); 59 | $backPharFile = $localPharDir.'/ez.phar.backup'; 60 | copy($localPharFile, $backPharFile); 61 | $assetUrl = $release->assets[0]->browser_download_url; 62 | $tempPharFile = $localPharDir.'/ez.phar.temp'; 63 | file_put_contents($tempPharFile, githubFetch($assetUrl, false)); 64 | copy($localPharFile.'.pubkey', $tempPharFile.'.pubkey'); 65 | 66 | $phar = new Phar($tempPharFile); 67 | $signature = $phar->getSignature(); 68 | if ('openssl' !== strtolower($signature['hash_type'])) { 69 | $this->io->error('Invalid Signature.'); 70 | 71 | return Command::FAILURE; 72 | } 73 | rename($tempPharFile, $localPharFile); 74 | chmod($localPharFile, fileperms($backPharFile)); 75 | unlink($tempPharFile.'.pubkey'); 76 | $this->io->writeln( 77 | "Updated from {$application->getVersion()} to {$release->tag_name}." 78 | ); 79 | 80 | return Command::SUCCESS; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/Configuration/Configuration.php: -------------------------------------------------------------------------------- 1 | getRootNode(); 21 | $rootNode 22 | ->children() 23 | ->arrayNode('docker') 24 | ->addDefaultsIfNotSet() 25 | ->children() 26 | ->scalarNode('compose_filename')->defaultValue('docker-compose.yml')->end() 27 | ->scalarNode('network_name')->defaultValue('default-ezlaunchpad')->end() 28 | ->scalarNode('network_prefix_port')->defaultValue(42)->end() 29 | ->scalarNode('host_machine_mapping')->defaultNull()->end() 30 | ->scalarNode('host_composer_cache_dir')->defaultNull()->end() 31 | ->end() 32 | ->end() 33 | ->arrayNode('provisioning') 34 | ->addDefaultsIfNotSet() 35 | ->children() 36 | ->scalarNode('folder_name')->defaultValue('provisioning')->end() 37 | ->end() 38 | ->end() 39 | ->arrayNode('composer') 40 | ->children() 41 | ->arrayNode('http_basic') 42 | ->prototype('array') 43 | ->children() 44 | ->scalarNode('host')->defaultNull()->end() 45 | ->scalarNode('login')->defaultNull()->end() 46 | ->scalarNode('password')->defaultNull()->end() 47 | ->end() 48 | ->end() 49 | ->end() 50 | ->arrayNode('token') 51 | ->prototype('array') 52 | ->children() 53 | ->scalarNode('host')->defaultNull()->end() 54 | ->scalarNode('value')->defaultNull()->end() 55 | ->end() 56 | ->end() 57 | ->end() 58 | ->end() 59 | ->end() 60 | ->scalarNode('last_update_check')->defaultNull()->end() 61 | ->end(); 62 | 63 | return $treeBuilder; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/Configuration/Project.php: -------------------------------------------------------------------------------- 1 | globalFilePath = $globalFilePath; 41 | $this->localFilePath = $localFilePath; 42 | $this->configurations = $configurations; 43 | } 44 | 45 | /** 46 | * @return array|mixed|null 47 | */ 48 | public function get(string $name) 49 | { 50 | if (strpos($name, '.')) { 51 | $parts = explode('.', $name); 52 | $array = $this->configurations; 53 | foreach ($parts as $part) { 54 | if (!isset($array[$part])) { 55 | return null; 56 | } 57 | $array = $array[$part]; 58 | } 59 | 60 | return $array; 61 | } 62 | 63 | return $this->configurations[$name] ?? null; 64 | } 65 | 66 | public function setLocal(string $name, $value): void 67 | { 68 | $this->set([$name => $value], 'local'); 69 | } 70 | 71 | public function setGlobal(string $name, $value): void 72 | { 73 | $this->set([$name => $value], 'global'); 74 | } 75 | 76 | public function setMultiLocal(array $keyValues): void 77 | { 78 | $this->set($keyValues, 'local'); 79 | } 80 | 81 | public function setMultiGlobal(array $keyValues): void 82 | { 83 | $this->set($keyValues, 'global'); 84 | } 85 | 86 | public function setEnvironment(string $environment): void 87 | { 88 | $this->environment = $environment; 89 | } 90 | 91 | /** 92 | * Store inMemory and in the good file. 93 | */ 94 | protected function set(array $keyValues, string $where = 'global'): void 95 | { 96 | $filePath = 'global' === $where ? $this->globalFilePath : $this->localFilePath; 97 | 98 | $fs = new Filesystem(); 99 | $config = $fs->exists($filePath) ? Yaml::parse(file_get_contents($filePath)) : []; 100 | 101 | foreach ($keyValues as $name => $value) { 102 | if (strpos($name, '.')) { 103 | $parts = explode('.', $name); 104 | $onFile = &$config; 105 | foreach ($parts as $part) { 106 | $onFile = &$onFile[$part]; 107 | } 108 | $onFile = $value; 109 | 110 | $inMemory = &$this->configurations; 111 | 112 | foreach ($parts as $part) { 113 | $inMemory = &$inMemory[$part]; 114 | } 115 | $inMemory = $value; 116 | } else { 117 | $this->configurations[$name] = $value; 118 | $config[$name] = $value; 119 | } 120 | } 121 | 122 | $yaml = Yaml::dump($config, 4); 123 | $fs->dumpFile($filePath, $yaml); 124 | } 125 | 126 | public function getDockerCompose(): DockerCompose 127 | { 128 | $projectPath = \dirname($this->localFilePath); 129 | 130 | return new DockerCompose( 131 | "{$projectPath}/"."{$this->get('provisioning.folder_name')}/". 132 | "{$this->environment}/{$this->get('docker.compose_filename')}" 133 | ); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/Console/Application.php: -------------------------------------------------------------------------------- 1 | 40 | * 41 | * * 42 | ___ 43 | | | | 44 | * / \ | | 45 | |--o|===|-| 46 | |---| | | 47 | * / \ | | 48 | | eZ | | | 49 | | |=| | 50 | Launchpad | | 51 | |_______| |_| 52 | |@| |@| | | 53 | ____\|/___________|_|_ 54 | 55 | '; 56 | 57 | /** 58 | * @var ContainerBuilder 59 | */ 60 | protected $container; 61 | 62 | public function setContainer(ContainerBuilder $container): self 63 | { 64 | $this->container = $container; 65 | 66 | return $this; 67 | } 68 | 69 | public function setEnv(string $env): self 70 | { 71 | $this->env = $env; 72 | 73 | return $this; 74 | } 75 | 76 | public function getLogo(): string 77 | { 78 | return self::$logo.$this->getLongVersion(); 79 | } 80 | 81 | public function getHelp(): string 82 | { 83 | return self::$logo.parent::getHelp(); 84 | } 85 | 86 | public function run(InputInterface $input = null, OutputInterface $output = null): int 87 | { 88 | // configure styles here 89 | return parent::run($input, $output); 90 | } 91 | 92 | public function doRun(InputInterface $input, OutputInterface $output): int 93 | { 94 | $this->loadConfiguration($input); 95 | 96 | // add the command from the configuration 97 | $commands = $this->container->findTaggedServiceIds('ezlaunchpad.command'); 98 | foreach ($commands as $def => $values) { 99 | $command = $this->container->get($def); 100 | if ($command instanceof Core\Command) { 101 | $this->add($command); 102 | } 103 | } 104 | 105 | return parent::doRun($input, $output); 106 | } 107 | 108 | protected function loadConfiguration(InputInterface $input): void 109 | { 110 | $appDir = __DIR__.'/../../'; 111 | $projectPath = getcwd(); 112 | $this->container->setParameter('app_dir', $appDir); 113 | $this->container->setParameter('app_env', $this->env); 114 | $this->container->setParameter('project_path', $projectPath); 115 | 116 | // Override the defaults values 117 | $globalFilePath = $input->getParameterOption(['--config', '-c'], EZ_HOME.'/ez.yml'); 118 | $fs = new Filesystem(); 119 | $configs = []; 120 | 121 | if ($fs->exists($globalFilePath)) { 122 | $configs[] = Yaml::parse(file_get_contents($globalFilePath)); 123 | } else { 124 | if ($input->hasParameterOption(['--config', '-c'])) { 125 | throw new FileNotFoundException("Configuraton file {$globalFilePath} not found."); 126 | } 127 | } 128 | 129 | // Load the local values and OVERRIDE 130 | $localFilePath = $projectPath.'/.ezlaunchpad.yml'; 131 | if ($fs->exists($localFilePath)) { 132 | $configs[] = Yaml::parse(file_get_contents($localFilePath)); 133 | } 134 | $processor = new Processor(); 135 | $configuration = new Configuration(); 136 | $processedConfiguration = $processor->processConfiguration( 137 | $configuration, 138 | $configs 139 | ); 140 | 141 | // set the dispatcher 142 | $this->container->setDefinition( 143 | 'event_dispatcher', 144 | (new Definition(EventDispatcher::class))->setPublic(true) 145 | ); 146 | 147 | // set the project configuration service 148 | $this->container->setDefinition( 149 | ProjectConfiguration::class, 150 | (new Definition( 151 | ProjectConfiguration::class, 152 | [ 153 | $globalFilePath, 154 | $localFilePath, 155 | $processedConfiguration, 156 | ] 157 | ))->setPublic(true) 158 | ); 159 | // Compile 160 | $this->compileConfiguration(); 161 | } 162 | 163 | /** 164 | * Find and compile the configuration. 165 | */ 166 | protected function compileConfiguration(): void 167 | { 168 | $this->container->compile(); 169 | $eventDispatcher = $this->container->get('event_dispatcher'); 170 | if ($eventDispatcher instanceof EventDispatcherInterface) { 171 | $this->setDispatcher( 172 | $eventDispatcher 173 | ); 174 | } 175 | } 176 | 177 | protected function getDefaultInputDefinition(): InputDefinition 178 | { 179 | $definition = parent::getDefaultInputDefinition(); 180 | $definition->addOption( 181 | new InputOption( 182 | '--config', 183 | '-c', 184 | InputOption::VALUE_REQUIRED, 185 | 'use the given file as configuration file, instead of the default one ('.EZ_HOME.'/ez.yml'.').' 186 | ) 187 | ); 188 | 189 | return $definition; 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /src/Console/ApplicationFactory.php: -------------------------------------------------------------------------------- 1 | addCompilerPass(new CommandPass($env)); 30 | $container->addCompilerPass(new RegisterListenersPass()); 31 | $loader = new YamlFileLoader($container, new FileLocator(__DIR__)); 32 | $loader->load(__DIR__.'/../../config/services.yml'); 33 | $loader->load(__DIR__.'/../../config/commands.yml'); 34 | $application = new Console\Application(); 35 | $application->setContainer($container); 36 | $application->setEnv($env); 37 | $application->setName('eZ Launchpad'); 38 | $application->setVersion('@package_version@'.(('prod' !== $env) ? '-dev' : '')); 39 | $application->setAutoExit($autoExit); 40 | 41 | return $application; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Core/Command.php: -------------------------------------------------------------------------------- 1 | io = new SymfonyStyle($input, $output); 55 | } 56 | 57 | public function setProjectConfiguration(ProjectConfiguration $configuration): self 58 | { 59 | $this->projectConfiguration = $configuration; 60 | 61 | return $this; 62 | } 63 | 64 | public function setAppDir(string $appDir): void 65 | { 66 | $this->appDir = $appDir; 67 | } 68 | 69 | public function getPayloadDir(): string 70 | { 71 | return "{$this->appDir}payload"; 72 | } 73 | 74 | public function setProjectPath(string $projectPath): void 75 | { 76 | $this->projectPath = $projectPath; 77 | } 78 | 79 | public function getProjectPath(): string 80 | { 81 | return $this->projectPath; 82 | } 83 | 84 | public function setRequiredRecipes(array $requiredRecipes): void 85 | { 86 | $this->requiredRecipes = NovaCollection($requiredRecipes); 87 | } 88 | 89 | public function getRequiredRecipes(): Collection 90 | { 91 | if (null === $this->requiredRecipes) { 92 | $this->requiredRecipes = NovaCollection([]); 93 | } 94 | 95 | return $this->requiredRecipes; 96 | } 97 | 98 | public function setOptimizer(OptimizerInterface $optimizer): void 99 | { 100 | $this->optimizer = $optimizer; 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/Core/DockerCommand.php: -------------------------------------------------------------------------------- 1 | addOption('env', 'e', InputOption::VALUE_REQUIRED, 'The Environment name.', 'dev'); 39 | $this->addOption( 40 | 'docker-env', 41 | 'd', 42 | InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 43 | 'Docker environment variables', 44 | [] 45 | ); 46 | } 47 | 48 | public function getDockerClient(): Docker 49 | { 50 | return $this->dockerClient; 51 | } 52 | 53 | protected function initialize(InputInterface $input, OutputInterface $output): void 54 | { 55 | parent::initialize($input, $output); 56 | $this->environment = $input->getOption('env'); 57 | $this->projectConfiguration->setEnvironment($this->environment); 58 | $fs = new Filesystem(); 59 | $currentPwd = $this->projectPath; 60 | $provisioningFolder = $this->projectConfiguration->get('provisioning.folder_name'); 61 | $dockerComposeFileName = $this->projectConfiguration->get('docker.compose_filename'); 62 | $dockerComposeFileFolder = NovaCollection([$currentPwd, $provisioningFolder, $this->environment])->implode( 63 | '/' 64 | ); 65 | 66 | if (!$fs->exists($dockerComposeFileFolder."/{$dockerComposeFileName}")) { 67 | throw new RuntimeException("There is no {$dockerComposeFileName} in {$dockerComposeFileFolder}"); 68 | } 69 | $options = [ 70 | 'compose-file' => $dockerComposeFileFolder."/{$dockerComposeFileName}", 71 | 'network-name' => $this->projectConfiguration->get('docker.network_name'), 72 | 'network-prefix-port' => $this->projectConfiguration->get('docker.network_prefix_port'), 73 | 'host-machine-mapping' => $this->projectConfiguration->get('docker.host_machine_mapping'), 74 | 'project-path' => $this->projectPath, 75 | 'provisioning-folder-name' => $provisioningFolder, 76 | 'composer-cache-dir' => $this->projectConfiguration->get('docker.host_composer_cache_dir'), 77 | ]; 78 | 79 | $this->dockerClient = new Docker($options, new ProcessRunner(), $this->optimizer); 80 | $this->taskExecutor = new TaskExecutor( 81 | $this->dockerClient, 82 | $this->projectConfiguration, 83 | $this->requiredRecipes, 84 | $input->getOption('docker-env') 85 | ); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/Core/DockerCompose.php: -------------------------------------------------------------------------------- 1 | compose = Yaml::parse(file_get_contents($filePath)); 23 | } 24 | 25 | public function getServices(): array 26 | { 27 | return $this->compose['services']; 28 | } 29 | 30 | public function hasService(string $name): bool 31 | { 32 | return isset($this->compose['services'][$name]); 33 | } 34 | 35 | public function dump(string $destination): void 36 | { 37 | $yaml = Yaml::dump($this->compose, 4); 38 | $fs = new Filesystem(); 39 | $fs->dumpFile($destination, $yaml); 40 | } 41 | 42 | public function filterServices(array $selectedServices): void 43 | { 44 | $services = []; 45 | foreach ($this->getServices() as $name => $service) { 46 | if (!\in_array($name, $selectedServices)) { 47 | continue; 48 | } 49 | $services[$name] = $service; 50 | } 51 | $this->compose['services'] = $services; 52 | } 53 | 54 | public function cleanForInitializeSkeleton(): void 55 | { 56 | $services = []; 57 | foreach ($this->getServices() as $name => $service) { 58 | // Solr is not managed here 59 | if ('solr' === $name) { 60 | continue; 61 | } 62 | 63 | if (isset($service['volumes'])) { 64 | $volumes = NovaCollection($service['volumes']); 65 | $service['volumes'] = $volumes->prune( 66 | function ($value) { 67 | return false === strpos($value, 'ezplatform'); 68 | } 69 | )->toArray(); 70 | } 71 | $services[$name] = $service; 72 | } 73 | $this->compose['services'] = $services; 74 | } 75 | 76 | public function cleanForInitialize(): void 77 | { 78 | $services = []; 79 | foreach ($this->getServices() as $name => $service) { 80 | // we don't need anything else for the init 81 | if (!\in_array($name, ['engine', 'db'])) { 82 | continue; 83 | } 84 | 85 | if (isset($service['volumes'])) { 86 | $volumes = NovaCollection($service['volumes']); 87 | $service['volumes'] = $volumes->prune( 88 | function ($value) { 89 | return false === strpos($value, 'ezplatform'); 90 | } 91 | )->toArray(); 92 | } 93 | if (isset($service['environment'])) { 94 | $environnementVars = NovaCollection($service['environment']); 95 | $service['environment'] = $environnementVars->prune( 96 | function ($value) { 97 | $vars = [ 98 | 'CUSTOM_CACHE_POOL', 99 | 'CACHE_HOST', 100 | 'CACHE_REDIS_PORT', 101 | 'CACHE_POOL', 102 | 'CACHE_DSN', 103 | 'SEARCH_ENGINE', 104 | 'SOLR_DSN', 105 | 'HTTPCACHE_PURGE_SERVER', 106 | 'SYMFONY_TMP_DIR', 107 | ]; 108 | 109 | return !preg_match( 110 | '/('.implode('|', $vars).')/', 111 | $value 112 | ); 113 | } 114 | )->values()->toArray(); 115 | } 116 | $services[$name] = $service; 117 | } 118 | $this->compose['services'] = $services; 119 | } 120 | 121 | public function removeUselessEnvironmentsVariables(): void 122 | { 123 | $services = []; 124 | foreach ($this->getServices() as $name => $service) { 125 | if (isset($service['environment'])) { 126 | $environnementVars = NovaCollection($service['environment']); 127 | $service['environment'] = $environnementVars->prune( 128 | function ($value) { 129 | if (!$this->hasService('solr')) { 130 | if (preg_match('/(SEARCH_ENGINE|SOLR_DSN)/', $value)) { 131 | return false; 132 | } 133 | } 134 | if (!$this->hasService('redis')) { 135 | if ( 136 | preg_match( 137 | '/(CUSTOM_CACHE_POOL|CACHE_HOST|CACHE_POOL|CACHE_DSN|CACHE_REDIS_PORT)/', 138 | $value 139 | ) 140 | ) { 141 | return false; 142 | } 143 | } 144 | if (!$this->hasService('varnish')) { 145 | if (preg_match('/(HTTPCACHE_PURGE_SERVER)/', $value)) { 146 | return false; 147 | } 148 | } 149 | 150 | return true; 151 | } 152 | )->values()->toArray(); 153 | } 154 | $services[$name] = $service; 155 | } 156 | $this->compose['services'] = $services; 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /src/Core/OSX/Optimizer/D4M.php: -------------------------------------------------------------------------------- 1 | getHostMapping(); 25 | MacOSPatherize($export); 26 | 27 | return $this->isResvReady() && $this->isExportReady($export) && self::isD4MScreenExist(); 28 | } 29 | 30 | public function hasPermission(SymfonyStyle $io): bool 31 | { 32 | list($export, $mountPoint) = $this->getHostMapping(); 33 | MacOSPatherize($export); 34 | 35 | $exportLine = "{$export} {$this->getExportOptions()}"; 36 | 37 | $this->standardNFSConfigurationMessage($io, $exportLine); 38 | $io->comment( 39 | " 40 | - Communicate with the Docker Moby VM and add the mount point 41 | {$export} -> {$mountPoint} 42 | " 43 | ); 44 | 45 | return $io->confirm('Do you want to setup your Mac as an NFS server and wire the MobbyVM through a screen?'); 46 | } 47 | 48 | public function getExportOptions(): string 49 | { 50 | return '-mapall='.getenv('USER').':staff localhost'; 51 | } 52 | 53 | public function optimize(SymfonyStyle $io, Command $command): bool 54 | { 55 | $isD4MScreenExist = self::isD4MScreenExist(); 56 | $this->setupNFS($io, $this->getExportOptions()); 57 | list($export, $mountPoint) = $this->getHostMapping(); 58 | MacOSPatherize($export); 59 | if (!$isD4MScreenExist) { 60 | $screenInit = 'screen -AmdS '.static::SCREEN_NAME; 61 | $screen = 'screen -S '.static::SCREEN_NAME.' -p 0 -X stuff'; 62 | $mountOptions = 'nolock,local_lock=all'; 63 | $mount = "mount -o {$mountOptions} \\$(route|awk '/default/ {print \\$2}'):{$export} {$mountPoint}"; 64 | $mobyTTY = '~/Library/Containers/com.docker.docker/Data/com.docker.driver.amd64-linux/tty'; 65 | 66 | exec("{$screenInit} {$mobyTTY}"); 67 | exec($screen.' $(printf "root\\r\\n")'); 68 | $commands = [ 69 | 'sleep 2', 70 | 'apk add --update nfs-utils', 71 | "mkdir -p {$mountPoint}", 72 | 'rpcbind -s', 73 | 'sleep 2', 74 | $mount, 75 | ]; 76 | $cmd = implode(' && ', $commands); 77 | exec($screen.' "'.$cmd.PHP_EOL.'"'); 78 | sleep(5); 79 | 80 | if (!self::isD4MScreenExist()) { 81 | $message = static::SCREEN_NAME.'screen failed to initiate. Mount point will not be ready.'; 82 | throw new RuntimeException($message); 83 | } 84 | $io->success('Moby VM mount succeed.'); 85 | } 86 | 87 | return true; 88 | } 89 | 90 | public static function isD4MScreenExist(): bool 91 | { 92 | $output = $return = null; 93 | exec('screen -list | grep -q "'.static::SCREEN_NAME.'";', $output, $return); 94 | 95 | return 0 === $return; 96 | } 97 | 98 | public function supports(int $version): bool 99 | { 100 | return $version < 1712; 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/Core/OSX/Optimizer/NFSAwareInterface.php: -------------------------------------------------------------------------------- 1 | success('NFSD restarted.'); 26 | 27 | return true; 28 | } 29 | 30 | public function getHostMapping(): array 31 | { 32 | $default = [getenv('HOME'), getenv('HOME')]; 33 | 34 | $currentMapping = $this->projectConfiguration->get('docker.host_machine_mapping'); 35 | if ($currentMapping) { 36 | return explode(':', $currentMapping); 37 | } 38 | $this->projectConfiguration->setGlobal('docker.host_machine_mapping', implode(':', $default)); 39 | 40 | return $default; 41 | } 42 | 43 | public function isExportReady($export): bool 44 | { 45 | $fs = new Filesystem(); 46 | if (!$fs->exists(NFSAwareInterface::EXPORTS)) { 47 | return false; 48 | } 49 | 50 | return NovaCollection(file(NFSAwareInterface::EXPORTS))->exists( 51 | function ($line) use ($export) { 52 | $export = addcslashes($export, '/.'); 53 | 54 | $line = trim($line); 55 | 56 | return 1 === preg_match("#^{$export}#", $line); 57 | } 58 | ); 59 | } 60 | 61 | public function isResvReady(): bool 62 | { 63 | $fs = new Filesystem(); 64 | if (!$fs->exists(NFSAwareInterface::RESV)) { 65 | return false; 66 | } 67 | 68 | return NovaCollection(file(NFSAwareInterface::RESV))->exists( 69 | function ($line) { 70 | $line = trim($line); 71 | if (preg_match("/^nfs\.server\.mount\.require_resv_port/", $line)) { 72 | if (strpos($line, '=')) { 73 | return '0' == trim(explode('=', $line)[1]); 74 | } 75 | } 76 | 77 | return false; 78 | } 79 | ); 80 | } 81 | 82 | public function setupNFS(SymfonyStyle $io, $exportOptions): bool 83 | { 84 | list($export, $mountPoint) = $this->getHostMapping(); 85 | $export = MacOSPatherize($export); 86 | 87 | $isResvReady = $this->isResvReady(); 88 | $isExportReady = $this->isExportReady($export); 89 | 90 | if (!$isResvReady) { 91 | exec( 92 | 'echo "nfs.server.mount.require_resv_port = 0" | sudo tee -a '.NFSAwareInterface::RESV, 93 | $output, 94 | $returnCode 95 | ); 96 | if (0 != $returnCode) { 97 | throw new RuntimeException('Writing in '.NFSAwareInterface::RESV.' failed.'); 98 | } 99 | $io->success(NFSAwareInterface::RESV.' updated.'); 100 | if (!$this->restartNFSD($io)) { 101 | return false; 102 | } 103 | } 104 | 105 | if (!$isExportReady) { 106 | $output = $returnCode = null; 107 | $exportLine = "{$export} {$exportOptions}"; 108 | exec("echo \"{$exportLine}\" | sudo tee -a ".NFSAwareInterface::EXPORTS, $output, $returnCode); 109 | if (0 != $returnCode) { 110 | throw new RuntimeException('Writing in '.NFSAwareInterface::EXPORTS.' failed.'); 111 | } 112 | $io->success(NFSAwareInterface::EXPORTS.' updated.'); 113 | if (!$this->restartNFSD($io)) { 114 | return false; 115 | } 116 | } 117 | 118 | return true; 119 | } 120 | 121 | public function standardNFSConfigurationMessage(SymfonyStyle $io, $exportLine): void 122 | { 123 | $io->caution('You are on Mac OS X, for optimal performance we recommend to mount the host through NFS.'); 124 | $io->comment( 125 | " 126 | This wizard is going to check and to do this step if required: 127 | - Add {$exportLine} in ".NFSAwareInterface::EXPORTS.' 128 | - Add nfs.server.mount.require_resv_port = 0 in '.NFSAwareInterface::RESV.' 129 | - Add restart your nfsd server: nfsd restart 130 | ' 131 | ); 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /src/Core/OSX/Optimizer/NFSVolumes.php: -------------------------------------------------------------------------------- 1 | getHostMapping(); 22 | $export = MacOSPatherize($export); 23 | 24 | return $this->isResvReady() && $this->isExportReady($export); 25 | } 26 | 27 | public function hasPermission(SymfonyStyle $io): bool 28 | { 29 | list($export, $mountPoint) = $this->getHostMapping(); 30 | $export = MacOSPatherize($export); 31 | $exportLine = "{$export} {$this->getExportOptions()}"; 32 | $this->standardNFSConfigurationMessage($io, $exportLine); 33 | 34 | return $io->confirm('Do you want to setup your Mac as an NFS server?'); 35 | } 36 | 37 | public function getExportOptions(): string 38 | { 39 | return '-mapall='.getenv('USER').':staff -alldirs localhost'; 40 | } 41 | 42 | public function optimize(SymfonyStyle $io, Command $command): bool 43 | { 44 | $this->setupNFS($io, $this->getExportOptions()); 45 | 46 | return true; 47 | } 48 | 49 | public function supports($version): bool 50 | { 51 | return $version >= 1803; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/Core/OSX/Optimizer/Optimizer.php: -------------------------------------------------------------------------------- 1 | projectConfiguration = $configuration; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Core/OSX/Optimizer/OptimizerInterface.php: -------------------------------------------------------------------------------- 1 | setTimeout(2 * 3600); 24 | 25 | if ($this->hasTty()) { 26 | $process->setTty(true); 27 | } 28 | 29 | try { 30 | return $process->mustRun(); 31 | } catch (ProcessFailedException $e) { 32 | $authorizedExitCodes = [ 33 | 129, // Hangup 34 | 130, // Interrupt 35 | ]; 36 | 37 | if (!\in_array($e->getProcess()->getExitCode(), $authorizedExitCodes)) { 38 | throw $e; 39 | } 40 | } 41 | 42 | return null; 43 | } 44 | 45 | public function hasTty(): bool 46 | { 47 | // Extracted from \Symfony\Component\Process\Process::setTty 48 | if ('\\' === \DIRECTORY_SEPARATOR) { 49 | // Windows platform does not have TTY 50 | $isTtySupported = false; 51 | } else { 52 | $pipes = null; 53 | // TTY mode requires /dev/tty to be read/writable. 54 | $isTtySupported = (bool) @proc_open( 55 | 'echo 1 >/dev/null', 56 | [ 57 | ['file', '/dev/tty', 'r'], 58 | ['file', '/dev/tty', 'w'], 59 | ['file', '/dev/tty', 'w'], 60 | ], 61 | $pipes 62 | ); 63 | } 64 | 65 | return $isTtySupported; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/Core/ProjectStatusDumper.php: -------------------------------------------------------------------------------- 1 | projectConfiguration = $projectConfiguration; 37 | } 38 | 39 | public function setDockerClient(Docker $dockerClient): void 40 | { 41 | $this->dockerClient = $dockerClient; 42 | } 43 | 44 | public function setIo(SymfonyStyle $io): void 45 | { 46 | $this->io = $io; 47 | } 48 | 49 | /** 50 | * @param Collection|string|array $options 51 | */ 52 | public function dump($options): void 53 | { 54 | if (\is_string($options)) { 55 | $options = str_split($options); 56 | } 57 | if (\is_array($options)) { 58 | $options = NovaCollection($options); 59 | } 60 | if ($options->contains('n')) { 61 | $this->dumpNetwork(); 62 | } 63 | if ($options->contains('c')) { 64 | $this->dumpComposeCommand(); 65 | } 66 | 67 | if ($options->contains('i')) { 68 | $this->dumpFirstTime(); 69 | } 70 | if ($options->contains('s')) { 71 | $this->dumpServiceAccess(); 72 | } 73 | } 74 | 75 | protected function dumpNetwork(): void 76 | { 77 | $this->io->title('Docker Network'); 78 | $this->dockerClient->ps(); 79 | } 80 | 81 | protected function dumpComposeCommand(): void 82 | { 83 | $composeCommand = $this->dockerClient->getComposeCommand(); 84 | $this->io->title("\nDocker Compose command"); 85 | $this->io->writeln($composeCommand); 86 | } 87 | 88 | /** 89 | * Dump Human service acccess. 90 | */ 91 | protected function dumpServiceAccess(): void 92 | { 93 | $portPrefix = $this->projectConfiguration->get('docker.network_prefix_port'); 94 | $dump = function ($title, $port, $suffix = '', $proto = 'http') use ($portPrefix) { 95 | $this->io->writeln( 96 | "{$title}: ". 97 | str_pad('', 1, "\t"). 98 | "{$proto}://localhost:{$portPrefix}{$port}{$suffix}" 99 | ); 100 | }; 101 | $this->io->title('Service Access'); 102 | 103 | $adminURI = '/ez'; 104 | if ($this->dockerClient->isEzPlatform2x()) { 105 | $adminURI = '/admin'; 106 | } 107 | $services = $this->projectConfiguration->getDockerCompose()->getServices(); 108 | if (isset($services['nginx'])) { 109 | $this->io->section('Project Web Access'); 110 | $dump('Nginx - Front-end (Development Mode)', '080'); 111 | $dump('Nginx - Back-end (Development Mode)', '080', $adminURI); 112 | 113 | if (isset($services['varnish'])) { 114 | $dump('Varnish - Front-end (Production Mode)', '082'); 115 | $dump('Varnish - Back-end (Production Mode)', '082', $adminURI); 116 | } else { 117 | $dump('Nginx - Front-end (Production Mode)', '081'); 118 | $dump('Nginx - Back-end (Production Mode)', '081', $adminURI); 119 | } 120 | } 121 | 122 | if (isset($services['db'])) { 123 | $this->io->section('Database Access'); 124 | $dump('MariaDB', '306', '', 'tcp'); 125 | } 126 | 127 | if (isset($services['solr'])) { 128 | $this->io->section('Solr Access'); 129 | $dump('Solr', '983'); 130 | } 131 | 132 | if (isset($services['mailcatcher']) || isset($services['adminer']) || isset($services['redisadmin'])) { 133 | $this->io->section('Tools'); 134 | if (isset($services['mailcatcher'])) { 135 | $dump('Mailcatcher', '180'); 136 | } 137 | if (isset($services['adminer'])) { 138 | $dump('Adminer', '084'); 139 | } 140 | if (isset($services['redisadmin'])) { 141 | $dump('Redis Admin', '083'); 142 | } 143 | } 144 | } 145 | 146 | /** 147 | * Dump first time stuff. 148 | */ 149 | protected function dumpFirstTime(): void 150 | { 151 | $this->io->title("\033[2J\033[0;0HWelcome in eZ Launchpad!"); 152 | $this->io->writeln( 153 | "Your project environment is now up and running. You have eZ Platform installed and running.\n". 154 | 'All the information are define in the section Service Access below.' 155 | ); 156 | 157 | $this->io->section('Code and CVS'); 158 | $this->io->writeln( 159 | "You will find the folder ezplatform which contains eZ Platform.\n". 160 | "The provisioning folder contains your local stack specifics.\n". 161 | ".gitignore have been provided then you can commit everything right now.\n" 162 | ); 163 | 164 | $this->io->section('Dump and storage'); 165 | $this->io->writeln( 166 | "Once intialized you can dump the database and the storage to include it in your repository.\n". 167 | '~ez dumpdata will create a data folder containing'. 168 | ' an archive for each (db.sql.gz and storage.tar.gz).' 169 | ); 170 | 171 | $this->io->section('Sharing'); 172 | $this->io->writeln( 173 | "Once commited and pushed, your collaborators can just git pull to get the project\n". 174 | "And then run ~/ez create to duplicate the environment.\n" 175 | ); 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /src/Core/TaskExecutor.php: -------------------------------------------------------------------------------- 1 | dockerClient = $dockerClient; 47 | $this->projectConfiguration = $configuration; 48 | $this->recipes = $recipes; 49 | $this->dockerEnvVars = $dockerEnvVars; 50 | } 51 | 52 | protected function checkRecipeAvailability(string $recipe): void 53 | { 54 | if (!$this->recipes->contains($recipe)) { 55 | throw new RuntimeException("Recipe {$recipe} is not available."); 56 | } 57 | } 58 | 59 | /** 60 | * @return Process[] 61 | */ 62 | public function composerInstall(): array 63 | { 64 | $recipe = 'composer_install'; 65 | $this->checkRecipeAvailability($recipe); 66 | 67 | $processes = []; 68 | // composer install 69 | $processes[] = $this->execute("{$recipe}.bash"); 70 | 71 | // Composer Configuration 72 | $httpBasics = $this->projectConfiguration->get('composer.http_basic'); 73 | if (\is_array($httpBasics)) { 74 | foreach ($httpBasics as $auth) { 75 | if (!isset($auth['host'], $auth['login'], $auth['password'])) { 76 | continue; 77 | } 78 | $processes[] = $this->globalExecute( 79 | '/usr/local/bin/composer config --global'. 80 | " http-basic.{$auth['host']} {$auth['login']} {$auth['password']}" 81 | ); 82 | } 83 | } 84 | 85 | $tokens = $this->projectConfiguration->get('composer.token'); 86 | if (\is_array($tokens)) { 87 | foreach ($tokens as $auth) { 88 | if (!isset($auth['host'], $auth['value'])) { 89 | continue; 90 | } 91 | $processes[] = $this->globalExecute( 92 | '/usr/local/bin/composer config --global'." github-oauth.{$auth['host']} {$auth['value']}" 93 | ); 94 | } 95 | } 96 | 97 | return $processes; 98 | } 99 | 100 | public function eZInstall(string $version, string $repository, string $initialData): Process 101 | { 102 | $recipe = 'ez_install'; 103 | $this->checkRecipeAvailability($recipe); 104 | 105 | return $this->execute("{$recipe}.bash {$repository} {$version} {$initialData}"); 106 | } 107 | 108 | public function ibexaInstall(string $version, string $repository, string $initialData): Process 109 | { 110 | $recipe = 'ibexa_install'; 111 | $this->checkRecipeAvailability($recipe); 112 | 113 | return $this->execute("{$recipe}.bash {$repository} {$version} {$initialData}"); 114 | } 115 | 116 | public function eZInstallSolr(): Process 117 | { 118 | $recipe = 'ez_install_solr'; 119 | $this->checkRecipeAvailability($recipe); 120 | 121 | return $this->execute( 122 | "{$recipe}.bash {$this->projectConfiguration->get('provisioning.folder_name')} COMPOSER_INSTALL" 123 | ); 124 | } 125 | 126 | public function indexSolr(): Process 127 | { 128 | $recipe = 'ez_install_solr'; 129 | $this->checkRecipeAvailability($recipe); 130 | 131 | return $this->execute( 132 | "{$recipe}.bash {$this->projectConfiguration->get('provisioning.folder_name')} INDEX" 133 | ); 134 | } 135 | 136 | public function createCore(): Process 137 | { 138 | $recipe = 'ez_install_solr'; 139 | $this->checkRecipeAvailability($recipe); 140 | 141 | $provisioningFolder = $this->projectConfiguration->get('provisioning.folder_name'); 142 | 143 | return $this->execute( 144 | "{$recipe}.bash {$provisioningFolder} CREATE_CORE", 145 | 'solr', 146 | 'solr' 147 | ); 148 | } 149 | 150 | public function eZCreate(): Process 151 | { 152 | $recipe = 'ez_create'; 153 | $this->checkRecipeAvailability($recipe); 154 | 155 | return $this->execute("{$recipe}.bash"); 156 | } 157 | 158 | public function dumpData(): Process 159 | { 160 | $recipe = 'create_dump'; 161 | $this->checkRecipeAvailability($recipe); 162 | 163 | return $this->execute("{$recipe}.bash"); 164 | } 165 | 166 | public function importData(): Process 167 | { 168 | $recipe = 'import_dump'; 169 | $this->checkRecipeAvailability($recipe); 170 | 171 | return $this->execute("{$recipe}.bash"); 172 | } 173 | 174 | public function runSymfomyCommand(string $arguments): Process 175 | { 176 | $consolePath = $this->dockerClient->isEzPlatform2x() ? 'bin/console' : 'app/console'; 177 | 178 | return $this->execute("ezplatform/{$consolePath} {$arguments}"); 179 | } 180 | 181 | public function runComposerCommand(string $arguments): Process 182 | { 183 | return $this->globalExecute( 184 | '/usr/local/bin/composer --working-dir='.$this->dockerClient->getProjectPathContainer().'/ezplatform '. 185 | $arguments 186 | ); 187 | } 188 | 189 | protected function execute(string $command, string $user = 'www-data', string $service = 'engine') 190 | { 191 | $command = $this->dockerClient->getProjectPathContainer().'/'.$command; 192 | 193 | return $this->globalExecute($command, $user, $service); 194 | } 195 | 196 | protected function globalExecute(string $command, string $user = 'www-data', string $service = 'engine') 197 | { 198 | $args = ['--user', $user]; 199 | 200 | foreach ($this->dockerEnvVars as $envVar) { 201 | $args = array_merge($args, ['--env', $envVar]); 202 | } 203 | 204 | return $this->dockerClient->exec($command, $args, $service); 205 | } 206 | } 207 | -------------------------------------------------------------------------------- /src/DependencyInjection/CommandPass.php: -------------------------------------------------------------------------------- 1 | env = $env; 30 | } 31 | 32 | public function process(ContainerBuilder $container): void 33 | { 34 | if (\in_array($this->env, ['dev', 'test'])) { 35 | $definition = new Definition(Test::class); 36 | $definition->addTag('ezlaunchpad.command'); 37 | $definition->setPublic(true); 38 | $container->setDefinition('ez.launchpad.test', $definition); 39 | $definition = new Definition(TestDockerClient::class); 40 | $definition->addTag('ezlaunchpad.command'); 41 | $definition->setPublic(true); 42 | $container->setDefinition('ez.launchpad.testdockerclient', $definition); 43 | } 44 | 45 | $commands = $container->findTaggedServiceIds('ezlaunchpad.command'); 46 | foreach ($commands as $id => $tags) { 47 | $commandDefinition = $container->getDefinition($id); 48 | $commandDefinition->addMethodCall('setProjectConfiguration', [new Reference(ProjectConfiguration::class)]); 49 | $commandDefinition->addMethodCall('setAppDir', [$container->getParameter('app_dir')]); 50 | $commandDefinition->addMethodCall('setProjectPath', [$container->getParameter('project_path')]); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/Listener/ApplicationUpdate.php: -------------------------------------------------------------------------------- 1 | parameters = $parameters; 34 | $this->projectConfiguration = $configuration; 35 | } 36 | 37 | public function onCommandAction(ConsoleCommandEvent $event): void 38 | { 39 | $command = $event->getCommand(); 40 | 41 | if (!$command instanceof BaseCommand || \in_array($command->getName(), ['self-update', 'rollback'])) { 42 | return; 43 | } 44 | 45 | $io = new SymfonyStyle($event->getInput(), $event->getOutput()); 46 | 47 | $authorized = [ 48 | 'list', 'help', 'test', 'docker:initialize:skeleton', 49 | 'docker:initialize_ibexa', 'docker:initialize', 'docker:create', 50 | 'self-update', 'rollback', 51 | ]; 52 | if (!\in_array($command->getName(), $authorized)) { 53 | $fs = new Filesystem(); 54 | $currentPwd = getcwd(); 55 | $provisioningFolder = $this->projectConfiguration->get('provisioning.folder_name'); 56 | $dockerComposeFileName = $this->projectConfiguration->get('docker.compose_filename'); 57 | $dockerEnv = $event->getInput()->hasOption('env') ? $event->getInput()->getOption( 58 | 'env' 59 | ) : 'dev'; 60 | $dockerComposeFileFolder = NovaCollection( 61 | [$currentPwd, $provisioningFolder, $dockerEnv] 62 | )->implode( 63 | '/' 64 | ); 65 | 66 | if (!$fs->exists($dockerComposeFileFolder."/{$dockerComposeFileName}")) { 67 | $io->error('Your are not in a folder managed by eZ Launchpad.'); 68 | $event->disableCommand(); 69 | $event->stopPropagation(); 70 | 71 | return; 72 | } 73 | } 74 | 75 | // do not check anything on Github Actions 76 | if (false !== getenv('GITHUB_ACTIONS')) { 77 | return; 78 | } 79 | 80 | // check last time check 81 | if (null != $this->projectConfiguration->get('last_update_check')) { 82 | $lastUpdate = Carbon::createFromTimestamp($this->projectConfiguration->get('last_update_check')); 83 | /** @var Carbon $lastUpdate */ 84 | $now = Carbon::now(); 85 | if ($now > $lastUpdate->subDays(3)) { 86 | return; 87 | } 88 | } 89 | 90 | $releaseUrl = $this->parameters['release_url']; 91 | $releases = githubFetch($releaseUrl); 92 | if (null === $releases) { 93 | $io->comment('Cannot find new releases, please try later.'); 94 | 95 | return; 96 | } 97 | $release = $releases[0]; 98 | $currentVersion = normalizeVersion($command->getApplication()->getVersion()); 99 | $lastVersion = normalizeVersion($release->tag_name); 100 | 101 | if ($lastVersion > $currentVersion) { 102 | $io->note('A new version of eZ Launchpad is available, please run self-update.'); 103 | sleep(2); 104 | } 105 | 106 | if (!\in_array($command->getName(), ['list', 'help'])) { 107 | $this->projectConfiguration->setLocal('last_update_check', time()); 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/Listener/CommandException.php: -------------------------------------------------------------------------------- 1 | getCommand(); 23 | if (!$command instanceof Command) { 24 | return; 25 | } 26 | 27 | // Ensure that docker is running 28 | $nonDockerCommandCheckList = [ 29 | 'docker:initialize:skeleton', 'docker:initialize', 30 | ]; 31 | if (($command instanceof DockerCommand) || (\in_array($command->getName(), $nonDockerCommandCheckList))) { 32 | $output = $return = null; 33 | exec('docker system info > /dev/null 2>&1', $output, $return); 34 | if (0 !== $return) { 35 | $io = new SymfonyStyle($event->getInput(), $event->getOutput()); 36 | $io->error('You need to start Docker before to run that command.'); 37 | $event->disableCommand(); 38 | $event->stopPropagation(); 39 | 40 | return; 41 | } 42 | } 43 | 44 | $fs = new Filesystem(); 45 | $command->getRequiredRecipes()->each( 46 | function ($recipe) use ($fs, $command) { 47 | $fs->copy( 48 | "{$command->getPayloadDir()}/recipes/{$recipe}.bash", 49 | "{$command->getProjectPath()}/{$recipe}.bash", 50 | true 51 | ); 52 | $fs->chmod("{$command->getProjectPath()}/{$recipe}.bash", 0755); 53 | } 54 | ); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Listener/CommandTerminate.php: -------------------------------------------------------------------------------- 1 | getCommand(); 21 | if (!$command instanceof Command) { 22 | return; 23 | } 24 | $fs = new Filesystem(); 25 | $command->getRequiredRecipes()->each( 26 | function ($recipe) use ($fs, $command) { 27 | $fs->remove("{$command->getProjectPath()}/{$recipe}.bash"); 28 | } 29 | ); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Listener/OSXListener.php: -------------------------------------------------------------------------------- 1 | optimizers = $optimizers; 28 | } 29 | 30 | public function onCommandAction(ConsoleCommandEvent $event): void 31 | { 32 | if (!EZ_ON_OSX) { 33 | return; 34 | } 35 | $command = $event->getCommand(); 36 | if (!$command instanceof Command) { 37 | return; 38 | } 39 | 40 | // don't bother for those command 41 | if (\in_array($command->getName(), ['self-update', 'rollback', 'list', 'help', 'test'])) { 42 | return; 43 | } 44 | 45 | $io = new SymfonyStyle($event->getInput(), $event->getOutput()); 46 | 47 | try { 48 | $version = $this->getDockerVersion(); 49 | foreach ($this->optimizers as $optimizer) { 50 | /** @var OptimizerInterface $optimizer */ 51 | if ( 52 | $optimizer->supports($version) && 53 | !$optimizer->isEnabled() && 54 | $optimizer->hasPermission($io) 55 | ) { 56 | $optimizer->optimize($io, $command); 57 | // only one allowed 58 | break; 59 | } 60 | } 61 | // one of them has been enable 62 | foreach ($this->optimizers as $optimizer) { 63 | /** @var OptimizerInterface $optimizer */ 64 | if ($optimizer->supports($version) && $optimizer->isEnabled()) { 65 | $command->setOptimizer($optimizer); 66 | } 67 | } 68 | } catch (\Exception $e) { 69 | $io->error($e->getMessage()); 70 | $event->disableCommand(); 71 | $event->stopPropagation(); 72 | 73 | return; 74 | } 75 | } 76 | 77 | protected function getDockerVersion(): int 78 | { 79 | $output = $return = null; 80 | exec('docker -v 2>/dev/null', $output, $return); 81 | if (0 !== $return) { 82 | throw new RuntimeException('You need to install Docker for Mac before to run that command.'); 83 | } 84 | list($version, $build) = explode(',', $output[0]); 85 | unset($build); 86 | $result = preg_replace('/([^ ]*) ([^ ]*) ([0-9\\.]*)-?([a-zA-z]*)/ui', '$3', $version); 87 | list($major, $minor, $patch) = explode('.', $result); 88 | unset($patch); 89 | $normalizedVersion = (int) $major * 100 + $minor; 90 | 91 | return (int) $normalizedVersion; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/bootstrap.php: -------------------------------------------------------------------------------- 1 | = 10) && ($minor >= 15)) || ($major >= 11); 55 | } else { 56 | $isCatalina = false; 57 | } 58 | } 59 | 60 | if (!$isCatalina) { 61 | return $path; 62 | } 63 | 64 | return str_replace('/Users', '/System/Volumes/Data/Users', $path); 65 | } 66 | 67 | function githubFetch(string $url, bool $toJson = true) 68 | { 69 | $context = stream_context_create( 70 | [ 71 | 'http' => [ 72 | 'method' => 'GET', 73 | 'header' => [ 74 | 'User-Agent: eZ Launchpad Installer', 75 | ], 76 | ], 77 | ] 78 | ); 79 | 80 | $content = @file_get_contents($url, false, $context); 81 | 82 | if (false === $content) { 83 | return null; 84 | } 85 | 86 | if (false === $toJson) { 87 | return $content; 88 | } 89 | 90 | return json_decode($content, false); 91 | } 92 | 93 | function normalizeVersion(string $versionName): int 94 | { 95 | if ('v' !== $versionName[0]) { 96 | return 0; 97 | } 98 | $version = substr($versionName, 1); 99 | $result = preg_replace('/([^ ]*) ([^ ]*) ([0-9.]*)-?([a-zA-z]*)/ui', '$3', $version); 100 | list($major, $minor, $patch) = explode('.', $result); 101 | 102 | return (int) $major * 10000 + (int) $minor * 100 + (int) $patch; 103 | } 104 | -------------------------------------------------------------------------------- /tests/Tests/Behat/Commands/Context.php: -------------------------------------------------------------------------------- 1 | tester = new ApplicationTester(ApplicationFactory::create(false, 'test', "Linux")); 28 | } 29 | 30 | /** 31 | * @When /^I run "([^"]*)" command$/ 32 | */ 33 | public function iRunCommand($name, $params = []): void 34 | { 35 | $parameters = ['command' => $name]; 36 | 37 | $parameters += $params; 38 | $this->tester->run($parameters); 39 | } 40 | 41 | /** 42 | * @Then /^I should see "([^"]*)"$/ 43 | */ 44 | public function iShouldSee($value): void 45 | { 46 | $matches = null; 47 | $output = $this->tester->getDisplay(); 48 | if (preg_match('/(.*) OR (.*)/us', $value)) { 49 | preg_match_all('/(.*) OR (.*)/us', $value, $matches); 50 | if ((strpos($output, $matches[1][0]) === false) && (strpos($output, $matches[2][0]) === false)) { 51 | throw new Exception( 52 | sprintf('Did not see either "%s" OR "%s" in output "%s"', $matches[1][0], $matches[2][0], $output) 53 | ); 54 | } 55 | } else { 56 | if (strpos($output, $value) === false) { 57 | throw new Exception(sprintf('Did not see "%s" in output "%s"', $value, $output)); 58 | } 59 | } 60 | } 61 | 62 | /** 63 | * @When /^I run "([^"]*)" command with parameter "([^"]*)": "([^"]*)"$/ 64 | */ 65 | public function iRunCommandWithParameter($name, $paramName, $params): void 66 | { 67 | $this->iRunCommand($name, [$paramName => explode(' ', $params)]); 68 | } 69 | 70 | /** 71 | * @Then /^I should see:$/ 72 | */ 73 | public function iShouldSee1(TableNode $table): void 74 | { 75 | foreach ($table->getRows() as $value) { 76 | $this->iShouldSee($value[0]); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /tests/Tests/Behat/Commands/features/test.feature: -------------------------------------------------------------------------------- 1 | Feature: Test command 2 | 3 | Scenario: Running test command 4 | When I run "test" command 5 | Then I should see "Test2" 6 | Then I should see: 7 | | Test1 | 8 | | Test3 | 9 | 10 | -------------------------------------------------------------------------------- /tests/Tests/Command/Test.php: -------------------------------------------------------------------------------- 1 | setName('test')->setDescription('Test'); 22 | $this->setHidden(true); 23 | } 24 | 25 | protected function execute(InputInterface $input, OutputInterface $output): int 26 | { 27 | $this->io->writeln('Test1'); 28 | $this->io->writeln('Test2'); 29 | $this->io->writeln('Test3'); 30 | 31 | return Command::SUCCESS; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /tests/Tests/Command/TestDockerClient.php: -------------------------------------------------------------------------------- 1 | setName('testdockerclient')->setDescription('Test Docker Client'); 22 | $this->setHidden(true); 23 | } 24 | 25 | protected function execute(InputInterface $input, OutputInterface $output): void 26 | { 27 | $this->io->writeln('Test1'); 28 | $this->io->writeln('Test2'); 29 | $this->io->writeln('Test3'); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tests/Tests/Unit/BehatTest.php: -------------------------------------------------------------------------------- 1 | createApplication(); 32 | $input = new ArrayInput(['--format' => ['progress'], '--config' => __DIR__.'/../../behat.yml']); 33 | $output = new ConsoleOutput(); 34 | $bApplication->setAutoExit(false); 35 | $result = $bApplication->run($input, $output); 36 | $this->assertEquals(0, $result); 37 | } catch (Exception $exception) { 38 | $this->fail($exception->getMessage()); 39 | } 40 | 41 | return true; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /tests/Tests/Unit/ConfigurationTest.php: -------------------------------------------------------------------------------- 1 | [ 23 | "compose_filename" => "docker-compose.yml", 24 | "network_prefix_port" => "42", 25 | "host_machine_mapping" => null, 26 | "network_name" => "default-ezlaunchpad", 27 | "host_composer_cache_dir" => null 28 | ], 29 | "provisioning" => [ 30 | "folder_name" => "provisioning" 31 | ], 32 | "last_update_check" => null 33 | ]; 34 | 35 | protected function process($configs): array 36 | { 37 | $processor = new Processor(); 38 | $configuration = new Configuration(); 39 | 40 | return $processor->processConfiguration( 41 | $configuration, 42 | $configs 43 | ); 44 | } 45 | 46 | public function testDefaultLoad(): void 47 | { 48 | $config = $this->process([]); 49 | $this->assertEquals(static::$defaultConfiguration, $config); 50 | } 51 | 52 | public function getYamlExamples(): array 53 | { 54 | return [ 55 | ['', 'ok'], 56 | [ 57 | ' 58 | last_update_check: 1491955697 59 | provisioning: 60 | folder_name: provisio 61 | docker: 62 | compose_filename: compose.yml 63 | network_name: something 64 | network_prefix_port: 43 65 | ', 'ok', 66 | ], 67 | [ 68 | ' 69 | provisioning: 70 | docker: 71 | ', 'default', 72 | ], 73 | [ 74 | ' 75 | docker: 76 | ', 'default', 77 | ], 78 | [ 79 | ' 80 | last_update_check: ~ 81 | ', 'default', 82 | ], 83 | [ 84 | ' 85 | provisioni2ng: 86 | ', 'exception', 87 | ], 88 | ]; 89 | } 90 | 91 | /** 92 | * @dataProvider getYamlExamples 93 | */ 94 | public function testYamlLoading($yaml, $expected): void 95 | { 96 | if ($expected === 'exception') { 97 | $this->expectException(Exception::class); 98 | } 99 | 100 | $configuration = Yaml::parse($yaml); 101 | $config = $this->process([$configuration]); 102 | 103 | if ($expected === 'ok') { 104 | $this->assertIsArray($config); 105 | } 106 | if ($expected === 'default') { 107 | $this->assertIsArray($config); 108 | $this->assertEquals(static::$defaultConfiguration, $config); 109 | } 110 | } 111 | 112 | /** 113 | * @dataProvider getYamlExamples 114 | */ 115 | public function testYamlException($yaml, $expected) 116 | { 117 | $this->expectException(InvalidConfigurationException::class); 118 | $configuration = Yaml::parse($yaml); 119 | $this->process([$configuration]); 120 | if ($expected !== 'exception') { 121 | throw new InvalidConfigurationException('mock'); 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /tests/Tests/Unit/DockerClientTest.php: -------------------------------------------------------------------------------- 1 | environmentVariables = $this->getDockerClientEnvironmentVariables(); 26 | } 27 | 28 | public function testEnvVariables(): void 29 | { 30 | $this->assertEquals($this->environmentVariables, $this->getDockerClient()->getComposeEnvVariables()); 31 | } 32 | 33 | public function testGetCommand(): void 34 | { 35 | $vars = NovaCollection($this->environmentVariables); 36 | 37 | $prefix = $vars->map( 38 | function ($value, $key) { 39 | return $key.'='.$value; 40 | } 41 | )->implode(' '); 42 | 43 | $expected = "{$prefix} docker-compose -p test -f ".$this->getDockerComposeFilePath(); 44 | $this->assertEquals($expected, $this->getDockerClient()->getComposeCommand()); 45 | } 46 | 47 | public function getTestedActions(): array 48 | { 49 | return [ 50 | ['ps', [[]], 'ps'], 51 | ['ps', [['-q']], 'ps -q'], 52 | ['ps', [['-q', '-ez']], 'ps -q -ez'], 53 | ['down', [[]], 'down'], 54 | ['down', [['-q']], 'down -q'], 55 | ['down', [['-q', '-ez']], 'down -q -ez'], 56 | ['start', ['plop'], 'start plop'], 57 | ['stop', ['plop'], 'stop plop'], 58 | ['restart', ['plop'], 'restart plop'], 59 | 60 | ['logs', [['-q', '-ez'], 'plop'], 'logs -q -ez plop'], 61 | ['up', [['-q', '-ez'], 'plop'], 'up -q -ez plop'], 62 | ['build', [['-q', '-ez'], 'plop'], 'build -q -ez plop'], 63 | ['remove', [['-q', '-ez'], 'plop'], 'rm -q -ez plop'], 64 | 65 | ['exec', ['/bin/bash', ['-q', '-ez'], 'plop'], 'exec -q -ez plop /bin/bash'], 66 | ['exec', ['/bin/bash', [], 'plop'], 'exec plop /bin/bash'], 67 | 68 | // no tty 69 | ['exec', ['/bin/bash', ['-q', '-ez'], 'plop'], 'exec -T -q -ez plop /bin/bash', false], 70 | ['exec', ['/bin/bash', [], 'plop'], 'exec -T plop /bin/bash', false], 71 | ]; 72 | } 73 | 74 | /** 75 | * @dataProvider getTestedActions 76 | */ 77 | public function testRun(string $method, array $args, string $expectedCommandSuffix, bool $hasTty = true): void 78 | { 79 | $client = $this->getDockerClient($hasTty); 80 | $mockedResults = \call_user_func_array([$client, $method], $args); 81 | 82 | $this->assertCount(2, $mockedResults); 83 | $this->assertEquals($mockedResults[1], $this->environmentVariables); 84 | 85 | $command = "docker-compose -p test -f ".$this->getDockerComposeFilePath(); 86 | $suffix = trim(str_replace($command, '', $mockedResults[0])); 87 | 88 | $this->assertEquals($expectedCommandSuffix, $suffix); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /tests/Tests/Unit/DockerComposeTest.php: -------------------------------------------------------------------------------- 1 | compose = new DockerCompose(__DIR__."/../../../payload/dev/docker-compose.yml"); 28 | } 29 | 30 | public function testFiltering(): void 31 | { 32 | $this->compose->filterServices(['engine', 'db']); 33 | $this->assertCount(2, $this->compose->getServices()); 34 | } 35 | 36 | public function testCleanupVolumesInitialize(): void 37 | { 38 | $this->compose->cleanForInitialize(); 39 | foreach ($this->compose->getServices() as $service) { 40 | if (!isset($service['volumes'])) { 41 | continue; 42 | } 43 | foreach ($service['volumes'] as $volumes) { 44 | $this->assertNotRegExp( 45 | "/ezplatform/", 46 | $volumes, 47 | 'It should not be any ezplatform mount for initialize.' 48 | ); 49 | } 50 | } 51 | } 52 | 53 | public function testCleanupEnvsInitialize(): void 54 | { 55 | $this->compose->cleanForInitialize(); 56 | foreach ($this->compose->getServices() as $name => $service) { 57 | if (!isset($service['environment'])) { 58 | continue; 59 | } 60 | foreach ($service['environment'] as $env) { 61 | $this->assertNotRegExp( 62 | "/(CUSTOM_CACHE_POOL|CACHE_HOST|CACHE_REDIS_PORT|SEARCH_ENGINE|SOLR_DSN)/", 63 | $env 64 | ); 65 | } 66 | } 67 | } 68 | 69 | public function getCleanEnvVarsData(): array 70 | { 71 | return [ 72 | [ 73 | ['engine', 'redis'], 74 | ['SEARCH_ENGINE', 'SOLR_DSN'] 75 | ], 76 | [ 77 | ['engine', 'solr'], 78 | ['CACHE_HOST', 'CACHE_REDIS_PORT', 'CACHE_REDIS_PORT'] 79 | ], 80 | [ 81 | ['engine'], 82 | ['CACHE_HOST', 'CACHE_REDIS_PORT', 'CACHE_REDIS_PORT', 'SEARCH_ENGINE', 'SOLR_DSN'] 83 | ] 84 | ]; 85 | } 86 | 87 | /** 88 | * @dataProvider getCleanEnvVarsData 89 | */ 90 | public function testCleanEnvVars($services, $toCheckVars): void 91 | { 92 | $this->compose->filterServices($services); 93 | $this->compose->removeUselessEnvironmentsVariables(); 94 | 95 | $environments = $this->compose->getServices()['engine']['environment']; 96 | $vars = []; 97 | 98 | foreach ($environments as $env) { 99 | if (!strpos($env, '=')) { 100 | continue; 101 | } 102 | list($key, $values) = explode("=", $env); 103 | 104 | $vars[] = $key; 105 | } 106 | foreach ($toCheckVars as $var) { 107 | $this->assertNotContains($var, $vars); 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /tests/Tests/Unit/ProjectConfigurationTest.php: -------------------------------------------------------------------------------- 1 | getConfiguration(); 45 | $this->assertEquals($projectConfiguration->get($key), $expectedValue); 46 | } 47 | 48 | public function testSet($where = 'local') 49 | { 50 | $method = "set".ucfirst($where); 51 | $var = 'docker.compose_filename'; 52 | $firstProjectConfiguration = $this->getConfiguration(); 53 | $this->assertEquals($firstProjectConfiguration->get($var), 'docker-compose-test.yml'); 54 | $firstProjectConfiguration->$method($var, 'docker-compose-test.yml_CHANGED'); 55 | $this->assertEquals($firstProjectConfiguration->get($var), 'docker-compose-test.yml_CHANGED'); 56 | $secondProjectConfiguration = $this->getConfiguration(); 57 | $this->assertEquals($secondProjectConfiguration->get($var), 'docker-compose-test.yml_CHANGED'); 58 | $this->assertEquals($firstProjectConfiguration, $secondProjectConfiguration); 59 | } 60 | 61 | public function testSetGlobal(): void 62 | { 63 | $this->testSet('global'); 64 | 65 | $configuration = $this->getConfiguration(); 66 | $configuration->setGlobal('provisioning.folder_name', 'untruc'); 67 | // change on the fly 68 | $this->assertEquals($configuration->get('provisioning.folder_name'), 'untruc'); 69 | 70 | // does not the next load 71 | $secondProjectConfiguration = $this->getConfiguration(); 72 | $this->assertEquals($secondProjectConfiguration->get('provisioning.folder_name'), 'provisioning_test'); 73 | } 74 | 75 | public function testDockerComposerGet(): void 76 | { 77 | $configuration = $this->getConfiguration(); 78 | $dockerCompose = $configuration->getDockerCompose(); 79 | $this->assertInstanceOf(DockerCompose::class, $dockerCompose); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /tests/Tests/Unit/RequiredFilesTest.php: -------------------------------------------------------------------------------- 1 | directories as $directory) { 24 | $data[] = [$directory, static::DIRECTORY]; 25 | } 26 | foreach ($box->files as $directory) { 27 | $data[] = [$directory, static::FILE]; 28 | } 29 | 30 | $data[] = [$box->main, static::FILE]; 31 | 32 | return $data; 33 | } 34 | 35 | public function testBoxJsonExist(): void 36 | { 37 | $this->assertFileExists($appDir = __DIR__."/../../../box.json"); 38 | } 39 | 40 | /** 41 | * @dataProvider getRequiredFiles 42 | */ 43 | public function testBoxFileIsPresent($file, $type): void 44 | { 45 | $appDir = __DIR__."/../../.."; 46 | $this->$type("{$appDir}/{$file}"); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /tests/Tests/Unit/TaskExecutorTest.php: -------------------------------------------------------------------------------- 1 | files()->in(__DIR__."/../../../payload/recipes")->name("*.bash"); 31 | 32 | $recipes = NovaCollection([]); 33 | foreach ($files as $file) { 34 | /** @var SplFileInfo $file */ 35 | $recipes->add(str_replace(".bash", "", $file->getFilename())); 36 | } 37 | $this->executor = new TaskExecutor($this->getDockerClient(), $this->getConfiguration(), $recipes); 38 | } 39 | 40 | /** 41 | * 42 | */ 43 | public function testComposerInstall(): void 44 | { 45 | $command = "docker-compose -p test -f ".$this->getDockerComposeFilePath(); 46 | $results = $this->executor->composerInstall(); 47 | $this->assertCount(3, $results); 48 | 49 | $suffixes = []; 50 | foreach ($results as $result) { 51 | $suffixes[] = trim(str_replace($command, '', $result[0])); 52 | } 53 | 54 | $startWith = "exec --user www-data engine"; 55 | $path = $this->getDockerClient()->getProjectPathContainer(); 56 | 57 | $this->assertEquals("{$startWith} {$path}/composer_install.bash", $suffixes[0]); 58 | $this->assertEquals( 59 | "{$startWith} /usr/local/bin/composer config --global http-basic.ez.no login novactive", 60 | $suffixes[1] 61 | ); 62 | $this->assertEquals( 63 | "{$startWith} /usr/local/bin/composer config --global http-basic.plopix.net login pass", 64 | $suffixes[2] 65 | ); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /tests/Tests/Unit/TestCase.php: -------------------------------------------------------------------------------- 1 | root = vfsStream::setup('ezlaunchpad'); 32 | $globalConfiguration = vfsStream::url("ezlaunchpad/ez.yml"); 33 | $localConfiguration = vfsStream::url("ezlaunchpad/.ezlaunchpad.yml"); 34 | 35 | file_put_contents( 36 | $globalConfiguration, 37 | ' 38 | docker: 39 | host_machine_mapping: "/Users/plopix/DOCKFILES:/data/DOCKER_SOURCES" 40 | host_composer_cache_dir: "/data/DOCKER_SOURCES/.composer_cache" 41 | compose_filename: docker-compose-test.yml 42 | 43 | provisioning: 44 | folder_name: "provisioning2ouf" 45 | 46 | composer: 47 | http_basic: 48 | ez: 49 | host: ez.no 50 | login: login 51 | password: novactive 52 | plopix: 53 | host: plopix.net 54 | login: login 55 | password: pass 56 | ' 57 | ); 58 | 59 | file_put_contents( 60 | $localConfiguration, 61 | ' 62 | last_update_check: 1491955697 63 | provisioning: 64 | folder_name: provisioning_test 65 | docker: 66 | network_name: newversion_test 67 | network_prefix_port: 123 68 | ' 69 | ); 70 | } 71 | 72 | protected function process($configs): array 73 | { 74 | $processor = new Processor(); 75 | $configuration = new Configuration(); 76 | 77 | return $processor->processConfiguration( 78 | $configuration, 79 | $configs 80 | ); 81 | } 82 | 83 | protected function getConfiguration(): ProjectConfiguration 84 | { 85 | $globalFile = $this->root->getChild('ez.yml')->url(); 86 | $localFile = $this->root->getChild('.ezlaunchpad.yml')->url(); 87 | 88 | $pConfiguration = new ProjectConfiguration( 89 | $globalFile, 90 | $localFile, 91 | $this->process( 92 | [ 93 | Yaml::parse(file_get_contents($globalFile)), 94 | Yaml::parse(file_get_contents($localFile)), 95 | ] 96 | ) 97 | ); 98 | $pConfiguration->setEnvironment('dev'); 99 | 100 | return $pConfiguration; 101 | } 102 | 103 | public function getDockerComposeFilePath(): string 104 | { 105 | return __DIR__."/../../../payload/dev/docker-compose.yml"; 106 | } 107 | 108 | public function getDockerClient(bool $hasTty = true): Docker 109 | { 110 | $options = [ 111 | 'compose-file' => $this->getDockerComposeFilePath(), 112 | 'network-name' => "test", 113 | 'network-prefix-port' => 42, 114 | 'project-path' => getcwd(), 115 | 'provisioning-folder-name' => 'provisioning', 116 | ]; 117 | 118 | $processRunnerMock = $this->getMockBuilder(ProcessRunner::class)->getMock(); 119 | 120 | $processRunnerMock 121 | ->method('run') 122 | ->will( 123 | $this->returnCallback( 124 | function () { 125 | return \func_get_args(); 126 | } 127 | ) 128 | ); 129 | 130 | $processRunnerMock 131 | ->method('hasTty') 132 | ->willReturn($hasTty); 133 | 134 | return new Docker($options, $processRunnerMock); 135 | } 136 | 137 | public function getDockerClientEnvironmentVariables(): array 138 | { 139 | return [ 140 | 'PROJECTNETWORKNAME' => 'test', 141 | "PROJECTPORTPREFIX" => 42, 142 | "PROJECTCOMPOSEPATH" => "../../", 143 | "PROVISIONINGFOLDERNAME" => "provisioning", 144 | "HOST_COMPOSER_CACHE_DIR" => MacOSPatherize(getenv('HOME')."/.composer/cache"), 145 | "DEV_UID" => getmyuid(), 146 | "DEV_GID" => getmygid(), 147 | 'COMPOSER_CACHE_DIR' => "/var/www/composer_cache", 148 | 'PROJECTMAPPINGFOLDER' => "/var/www/html/project", 149 | 'BLACKFIRE_CLIENT_ID' => getenv('BLACKFIRE_CLIENT_ID'), 150 | 'BLACKFIRE_CLIENT_TOKEN' => getenv('BLACKFIRE_CLIENT_TOKEN'), 151 | 'BLACKFIRE_SERVER_ID' => getenv('BLACKFIRE_SERVER_ID'), 152 | 'BLACKFIRE_SERVER_TOKEN' => getenv('BLACKFIRE_SERVER_TOKEN'), 153 | 'DOCKER_HOST' => getenv('DOCKER_HOST'), 154 | 'DOCKER_CERT_PATH' => getenv('DOCKER_CERT_PATH'), 155 | 'DOCKER_TLS_VERIFY' => getenv('DOCKER_TLS_VERIFY'), 156 | 'PATH' => getenv('PATH'), 157 | 'XDEBUG_ENABLED' => getenv('XDEBUG_ENABLED') === false ? '0' : '1' 158 | ]; 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /tests/behat.yml: -------------------------------------------------------------------------------- 1 | default: 2 | calls: 3 | #php -r "echo E_ALL & ~E_USER_DEPRECATED;" 4 | error_reporting: 16383 5 | suites: 6 | commands: 7 | paths: 8 | - Tests/Behat/Commands 9 | contexts: 10 | - eZ\Launchpad\Tests\Behat\Commands\Context 11 | -------------------------------------------------------------------------------- /tests/bootstrap.php: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 | ./Tests/Unit 21 | 22 | 23 | 24 | 25 | ../src/ 26 | 27 | ../src/bootstrap.php 28 | ../src/functions.php 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /tests/postman/collection-1x.json: -------------------------------------------------------------------------------- 1 | { 2 | "variables": [], 3 | "info": { 4 | "name": "eZ Launchpad", 5 | "_postman_id": "8c9b1b7c-3cab-0d63-5514-e4712892b3de", 6 | "description": "A Collection to test that eZ Launchpad initialize correctly", 7 | "schema": "https://schema.getpostman.com/json/collection/v2.0.0/collection.json" 8 | }, 9 | "item": [ 10 | { 11 | "name": "Load Home Page", 12 | "event": [ 13 | { 14 | "listen": "test", 15 | "script": { 16 | "type": "text/javascript", 17 | "exec": [ 18 | "tests[\"Page loaded\"] = responseBody.has(\"eZ Platform\");", 19 | "tests[\"Status code is 200\"] = responseCode.code === 200;" 20 | ] 21 | } 22 | } 23 | ], 24 | "request": { 25 | "url": "http://localhost:42080/", 26 | "method": "GET", 27 | "header": [], 28 | "body": {}, 29 | "description": "" 30 | }, 31 | "response": [] 32 | }, 33 | { 34 | "name": "Load Admin Page", 35 | "event": [ 36 | { 37 | "listen": "test", 38 | "script": { 39 | "type": "text/javascript", 40 | "exec": [ 41 | "tests[\"Page loaded\"] = responseBody.has(\"eZ Platform UI\");", 42 | "tests[\"Page loaded 2\"] = responseBody.has(\"Loading the application...\");", 43 | "tests[\"Status code is 200\"] = responseCode.code === 200;" 44 | ] 45 | } 46 | } 47 | ], 48 | "request": { 49 | "url": "http://localhost:42080/ez", 50 | "method": "GET", 51 | "header": [], 52 | "body": {}, 53 | "description": "" 54 | }, 55 | "response": [] 56 | }, 57 | { 58 | "name": "Front Login Failure - DB Test", 59 | "event": [ 60 | { 61 | "listen": "test", 62 | "script": { 63 | "type": "text/javascript", 64 | "exec": [ 65 | "tests[\"Login Failed\"] = responseBody.has(\"Bad credentials\");", 66 | "tests[\"Status code is 200\"] = responseCode.code === 200;" 67 | ] 68 | } 69 | } 70 | ], 71 | "request": { 72 | "url": "http://localhost:42080/login_check", 73 | "method": "POST", 74 | "header": [], 75 | "body": { 76 | "mode": "formdata", 77 | "formdata": [ 78 | { 79 | "key": "_username", 80 | "value": "Plopix", 81 | "description": "", 82 | "type": "text" 83 | }, 84 | { 85 | "key": "_password", 86 | "value": "Novactive", 87 | "description": "", 88 | "type": "text" 89 | } 90 | ] 91 | }, 92 | "description": "" 93 | }, 94 | "response": [] 95 | }, 96 | { 97 | "name": "Front Login OK - DB Test", 98 | "event": [ 99 | { 100 | "listen": "test", 101 | "script": { 102 | "type": "text/javascript", 103 | "exec": [ 104 | "tests[\"Login success\"] = !responseBody.has(\"Bad credentials\");", 105 | "tests[\"Status code is 200\"] = responseCode.code === 200;" 106 | ] 107 | } 108 | } 109 | ], 110 | "request": { 111 | "url": "http://localhost:42080/login_check", 112 | "method": "POST", 113 | "header": [], 114 | "body": { 115 | "mode": "formdata", 116 | "formdata": [ 117 | { 118 | "key": "_username", 119 | "value": "admin", 120 | "description": "", 121 | "type": "text" 122 | }, 123 | { 124 | "key": "_password", 125 | "value": "publish", 126 | "description": "", 127 | "type": "text" 128 | } 129 | ] 130 | }, 131 | "description": "" 132 | }, 133 | "response": [] 134 | } 135 | ] 136 | } 137 | -------------------------------------------------------------------------------- /tests/postman/collection-2x.json: -------------------------------------------------------------------------------- 1 | { 2 | "info": { 3 | "name": "eZ Launchpad", 4 | "_postman_id": "8c9b1b7c-3cab-0d63-5514-e4712892b3de", 5 | "description": "A Collection to test that eZ Launchpad initialize correctly", 6 | "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" 7 | }, 8 | "item": [ 9 | { 10 | "name": "Load Home Page", 11 | "event": [ 12 | { 13 | "listen": "test", 14 | "script": { 15 | "type": "text/javascript", 16 | "exec": [ 17 | "tests[\"Status code is 200\"] = responseCode.code === 200;" 18 | ] 19 | } 20 | } 21 | ], 22 | "request": { 23 | "method": "GET", 24 | "header": [], 25 | "body": {}, 26 | "url": { 27 | "raw": "http://localhost:42080/", 28 | "protocol": "http", 29 | "host": [ 30 | "localhost" 31 | ], 32 | "port": "42080", 33 | "path": [ 34 | "" 35 | ] 36 | }, 37 | "description": "" 38 | }, 39 | "response": [] 40 | }, 41 | { 42 | "name": "Load Admin Page", 43 | "event": [ 44 | { 45 | "listen": "test", 46 | "script": { 47 | "id": "19d338c4-e169-49b3-a383-766756df60ce", 48 | "type": "text/javascript", 49 | "exec": [ 50 | "tests[\"Status code is 200\"] = responseCode.code === 200;" 51 | ] 52 | } 53 | } 54 | ], 55 | "request": { 56 | "method": "GET", 57 | "header": [], 58 | "body": {}, 59 | "url": { 60 | "raw": "http://localhost:42080/admin/login", 61 | "protocol": "http", 62 | "host": [ 63 | "localhost" 64 | ], 65 | "port": "42080", 66 | "path": [ 67 | "admin", 68 | "login" 69 | ] 70 | }, 71 | "description": "" 72 | }, 73 | "response": [] 74 | } 75 | ] 76 | } 77 | --------------------------------------------------------------------------------