diff --git a/.docker/Dockerfile b/.docker/Dockerfile new file mode 100644 index 00000000..f2169746 --- /dev/null +++ b/.docker/Dockerfile @@ -0,0 +1,27 @@ +ARG PHP_VERSION=7.2 +FROM php:${PHP_VERSION}-alpine + +ARG XDEBUG=0 + +COPY .docker/entrypoint.sh /usr/local/bin/ + +RUN apk add --no-cache \ + autoconf \ + make \ + g++ \ + bash \ + git \ + openssl-dev + +RUN echo -e 'memory_limit=2G' > /usr/local/etc/php/conf.d/memory.ini +RUN set -o pipefail && curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer +RUN if [ ${PHP_VERSION:0:3} == "5.6" ] ; then \ + pecl install mongo && docker-php-ext-enable mongo ; \ + else \ + pecl install mongodb && docker-php-ext-enable mongodb ; \ + fi +RUN if [ ${XDEBUG} == "1" ] ; then pecl install xdebug && docker-php-ext-enable xdebug ; fi +RUN composer config --global "platform.ext-mongo" "1.999" ; + +WORKDIR /docker +ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] diff --git a/.docker/ascii.art b/.docker/ascii.art new file mode 100644 index 00000000..1b47addf --- /dev/null +++ b/.docker/ascii.art @@ -0,0 +1,20 @@ ++-------------------------+ && %&&( +|ooooo:. .:ooooooooooooo| &&&&&&&&&&&& +|ooooo. ::ooooooooooo| ,& &&& +|ooooo:. .oooooooooo| ,//&& (&&&&& +|ooooooo:. .:ooooooo| / ////&&%&&% #(&&&& +|ooooo:... :ooooo| ,*////######&&& &&&&& +|ooo:. .. .:ooo| //////########&&&&&&&&& +|o:. :ooo. :o| ///////#########&&&&&&& +|o. .:oooo. o| ////////&######&&&&&&& +|. . ..ooooo.. .| &%(/////&&&&&####&&&&&&& +| :oooooooooooooo. | &&& &&&&&&##&&&&&&&& +| .:::::::oooooo: | / * & (&&&&&&&%&&&&&&&&&( +|. .:oooo:. .| & % / &&&&&&&&& &&& +|o. :oooo:. .o| & ( & ( . &&&&& %&& +|oo. :o::. .oo| ( & &&&& +|ooo:.. .oooo| ** * &&&& +|oooooo:.. ..:oooooo| / ++-------------------------+ / / + + Doctrine in Apigility diff --git a/.docker/entrypoint.sh b/.docker/entrypoint.sh new file mode 100755 index 00000000..ec0ac712 --- /dev/null +++ b/.docker/entrypoint.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +while ! nc -z ${MONGO_HOST:-mongo} ${MONGO_PORT:-27017}; + do sleep 1; + done + +cat ./.docker/ascii.art + +exec "$@" diff --git a/.gitattributes b/.gitattributes index 2ca26bea..8bd0baf5 100644 --- a/.gitattributes +++ b/.gitattributes @@ -5,3 +5,5 @@ .travis.yml export-ignore phpcs.xml export-ignore phpunit.xml.dist export-ignore +docker-compose.yml export-ignore +/.docker export-ignore diff --git a/.gitignore b/.gitignore index 7fffcbdb..970d4ecc 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ test/data/ test/assets/module/*/config/module.config.php clover.xml coveralls-upload.json +docker-compose.override.yml diff --git a/.travis.yml b/.travis.yml index 4bc4ae69..bfa98267 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,20 +1,11 @@ sudo: false - language: php -services: - - mongodb - -cache: - directories: - - $HOME/.composer/cache - env: global: - - COMPOSER_ARGS="--no-interaction" - ADAPTER_DEPS="alcaeus/mongo-php-adapter" - COVERAGE_DEPS="php-coveralls/php-coveralls" - - MONGO_DRIVER=mongo + - COMPOSER_ARGS="--no-interaction" matrix: include: @@ -31,63 +22,59 @@ matrix: - php: 7 env: - DEPS=lowest - - MONGO_DRIVER=mongodb - php: 7 env: - DEPS=locked - LEGACY_DEPS="doctrine/doctrine-module doctrine/doctrine-orm-module phpunit/phpunit zendframework/zend-code" - - MONGO_DRIVER=mongodb - php: 7 env: - DEPS=latest - - MONGO_DRIVER=mongodb - php: 7.1 env: - DEPS=lowest - - MONGO_DRIVER=mongodb - php: 7.1 env: - DEPS=locked - CS_CHECK=true - TEST_COVERAGE=true - - MONGO_DRIVER=mongodb - php: 7.1 env: - DEPS=latest - - MONGO_DRIVER=mongodb - php: 7.2 env: - DEPS=lowest - - MONGO_DRIVER=mongodb - php: 7.2 env: - DEPS=locked - - MONGO_DRIVER=mongodb - php: 7.2 env: - DEPS=latest - - MONGO_DRIVER=mongodb before_install: - - if [[ $TEST_COVERAGE != 'true' ]]; then phpenv config-rm xdebug.ini || return 0 ; fi + - shopt -s expand_aliases + - alias composer="travis_retry docker-compose run --rm php composer" + - alias php="travis_retry docker-compose run --rm php php" + - docker-compose build --build-arg PHP_VERSION=${TRAVIS_PHP_VERSION} --build-arg XDEBUG=${TEST_COVERAGE:+1} --no-cache php + - composer --version + - php -v + - php -m install: - - yes '' | pecl -q install -f $MONGO_DRIVER - - composer config platform.ext-mongo '1.999' - - travis_retry composer install $COMPOSER_ARGS --ignore-platform-reqs - - if [[ $LEGACY_DEPS != '' ]]; then travis_retry composer update $COMPOSER_ARGS --with-dependencies $LEGACY_DEPS ; fi - - if [[ $DEPS == 'latest' ]]; then travis_retry composer update $COMPOSER_ARGS ; fi - - if [[ $DEPS == 'lowest' ]]; then travis_retry composer update --prefer-lowest --prefer-stable $COMPOSER_ARGS ; fi - - if [[ $MONGO_DRIVER == 'mongodb' ]]; then travis_retry composer require --dev $COMPOSER_ARGS $ADAPTER_DEPS ; fi - - if [[ $TEST_COVERAGE == 'true' ]]; then travis_retry composer require --dev $COMPOSER_ARGS $COVERAGE_DEPS ; fi + - composer install $COMPOSER_ARGS --ignore-platform-reqs + - if [[ $LEGACY_DEPS != '' ]]; then composer update $COMPOSER_ARGS --with-dependencies $LEGACY_DEPS ; fi + - if [[ $DEPS == 'latest' ]]; then composer update $COMPOSER_ARGS ; fi + - if [[ $DEPS == 'lowest' ]]; then composer update --prefer-lowest --prefer-stable $COMPOSER_ARGS ; fi + - if [[ $TRAVIS_PHP_VERSION != "5.6" ]] ; then composer require --dev $COMPOSER_ARGS $ADAPTER_DEPS ; fi + - if [[ $TEST_COVERAGE == 'true' ]]; then composer require --dev $COMPOSER_ARGS $COVERAGE_DEPS ; fi - stty cols 120 && composer show + - composer show script: - if [[ $TEST_COVERAGE == 'true' ]]; then composer test-coverage ; else composer test ; fi - if [[ $CS_CHECK == 'true' ]]; then composer cs-check ; fi after_script: - - if [[ $TEST_COVERAGE == 'true' ]]; then travis_retry php vendor/bin/php-coveralls -v ; fi + - if [[ $TEST_COVERAGE == 'true' ]]; then php vendor/bin/php-coveralls -v ; fi notifications: email: false diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 62fdd144..c36ed6f4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -39,10 +39,41 @@ contributors a chance to resolve the vulnerability and issue a new release prior to any public exposure; this helps protect Apigility users, and provides them with a chance to upgrade and/or update in order to protect their applications. -For sensitive email communications, please use +For sensitive email communications, please use [our PGP key](http://framework.zend.com/zf-security-pgp-key.asc). -## RUNNING TESTS +## DOCKER FOR DEVELOPMENT + +This library requires a running instance of Mongo in order to run and pass +the unit tests. It is not expected for each developer to configure their +individual machine to match this environment so Docker is provided. + +### RUNNING DOCKER-COMPOSE + +You will need docker-compose installed on your machine. +Docker supports many PHP versions. You may specify the version of PHP you +want (default:7.2) to build against when running `docker-compose` and flag XDEBUG to +install (1) or not (default:0). + +Next, from the root directory of this project, run + +``` +$ docker-compose build +``` + +To build a custom container use the flags + +``` +$ docker-compose build --build-arg PHP_VERSION=7.1 --build-arg XDEBUG=1 +``` + +To connect to the php container for development run + +``` +$ docker-compose run --rm php bash +``` + +### RUNNING UNIT TESTS IN THE CONTAINER First, use [Composer](https://getcomposer.org) to install all dependencies: @@ -56,6 +87,26 @@ To run tests: $ composer test ``` +### RUNNING UNIT TESTS ON DOCKER + +You may run the unit tests through the container without running bash via + +``` +$ docker-compose run --rm php composer test +``` + +### DOCKER AND CONTINUOUS INTEGRATION + +When you have made a change and created a pull request for it Travis-CI is used +to validate the build. For this a Docker container is created on travis for each +build matrix and the unit tests are ran identical to running unit tests on Docker locally. + +### OVERRIDING DOCKER FOR LOCAL DEVELOPMENT + +Docker supports overriding the docker-compose.yml file. See +[https://docs.docker.com/compose/extends/#multiple-compose-files](https://docs.docker.com/compose/extends/#multiple-compose-files) +for more information. + ## CODING STANDARDS While Apigility uses Zend Framework 2 coding standards, in practice, we check diff --git a/composer.json b/composer.json index 868b9c6f..b3deef9e 100644 --- a/composer.json +++ b/composer.json @@ -70,7 +70,12 @@ "ZFTest\\Apigility\\Doctrine\\": "test/src/" } }, + "bin": [ + "./scripts/mongodb-shim" + ], "scripts": { + "pre-install-cmd": "mongodb-shim", + "pre-update-cmd": "mongodb-shim", "check": [ "@cs-check", "@test" diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..0bf06a6a --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,19 @@ +version: "3" +services: + php: + build: + context: . + dockerfile: .docker/Dockerfile + args: + - PHP_VERSION=${PHP_VERSION:-7.2} + - XDEBUG=${XDEBUG:-0} + depends_on: + - mongo + volumes: + - ./:/docker + environment: + - MONGO_HOST=mongo + - MONGO_PORT=27017 + + mongo: + image: mongo:latest diff --git a/scripts/mongodb-shim b/scripts/mongodb-shim new file mode 120000 index 00000000..0b6dfe48 --- /dev/null +++ b/scripts/mongodb-shim @@ -0,0 +1 @@ +mongodb-shim.php \ No newline at end of file diff --git a/scripts/mongodb-shim.php b/scripts/mongodb-shim.php new file mode 100755 index 00000000..fbefca7f --- /dev/null +++ b/scripts/mongodb-shim.php @@ -0,0 +1,37 @@ +#!/usr/bin/env php + + */ + +$version = explode('.', PHP_VERSION); +if ($version[0] <= 5) { + return; +} + +$config = json_decode(file_get_contents(__DIR__ . '/../composer.json'), true); +$change = false; + +if (! in_array('alcaeus/mongo-php-adapter', array_keys($config['require']))) { + $config['require']['alcaeus/mongo-php-adapter'] = '^1.1'; + $change = true; +} + +if (! isset($config['config']) + || ! isset($config['config']['platform']) + || ! isset($config['config']['platform']['ext-mongo']) +) { + $config['config']['platform']['ext-mongo'] = '1.6.16'; + $change = true; +} + +if ($change) { + echo "Including MongoDB shim alcaeus/mongo-php-adapter\n"; + + file_put_contents( + __DIR__ . '/../composer.json', + json_encode($config, JSON_PRETTY_PRINT + JSON_UNESCAPED_SLASHES) + ); +} diff --git a/test/config/ODM/local.php b/test/config/ODM/local.php index 33f3db12..1c167d45 100644 --- a/test/config/ODM/local.php +++ b/test/config/ODM/local.php @@ -8,8 +8,8 @@ 'doctrine' => [ 'connection' => [ 'odm_default' => [ - 'server' => 'localhost', - 'port' => '27017', + 'server' => getenv('MONGO_HOST') ?: 'localhost', + 'port' => getenv('MONGO_PORT') ?: '27017', 'user' => '', 'password' => '', 'dbname' => 'zf_apigility_doctrine_server_test', diff --git a/test/src/Admin/Model/DoctrineAutodiscoveryModelTest.php b/test/src/Admin/Model/DoctrineAutodiscoveryModelTest.php index 6ea39cfe..6dd24207 100644 --- a/test/src/Admin/Model/DoctrineAutodiscoveryModelTest.php +++ b/test/src/Admin/Model/DoctrineAutodiscoveryModelTest.php @@ -29,17 +29,34 @@ public function testORMAutodiscoveryEntitiesWithFields() $this->assertInternalType('array', $result); $this->assertCount(3, $result); - $this->assertEquals(Album::class, $result[0]['entity_class']); - $this->assertEquals('Album', $result[0]['service_name']); - $this->assertCount(2, $result[0]['fields']); + $resultProcessed = []; + foreach ($result as $row) { + switch ($row['entity_class']) { + case Album::class: + $this->assertEquals('Album', $row['service_name']); + $this->assertCount(2, $row['fields']); + break; + case Artist::class: + $this->assertEquals('Artist', $row['service_name']); + $this->assertCount(2, $row['fields']); + break; + case Product::class: + $this->assertEquals('Product', $row['service_name']); + $this->assertCount(1, $row['fields']); + break; + default: + throw new \Exception("Unexpected result: " . $row['entity_class']); + } - $this->assertEquals(Artist::class, $result[1]['entity_class']); - $this->assertEquals('Artist', $result[1]['service_name']); - $this->assertCount(2, $result[1]['fields']); + if (isset($resultProcessed[$row['entity_class']])) { + $resultProcessed[$row['entity_class']] ++; + } else { + $resultProcessed[$row['entity_class']] = 1; + } + } - $this->assertEquals(Product::class, $result[2]['entity_class']); - $this->assertEquals('Product', $result[2]['service_name']); - $this->assertCount(1, $result[2]['fields']); + $this->assertEquals(3, sizeof($resultProcessed)); + $this->assertEquals(3, array_sum($resultProcessed)); } public function testODMAutodiscoveryEntitiesWithFields()