From acf3cf9c74206d40547e5d82b62e147e37956d92 Mon Sep 17 00:00:00 2001 From: Damiano Petrungaro Date: Fri, 16 Feb 2018 18:15:53 +0100 Subject: [PATCH] Initial commit --- .gitignore | 1 + .php-commitizen.php | 30 + .scrutinizer.yml | 18 + LICENSE | 21 + README.md | 62 + bin/php-commitizen | 24 + composer.json | 41 + composer.lock | 1918 +++++++++++++++++++ phpunit.xml | 22 + src/CommitCommand.php | 203 ++ src/Configuration.php | 201 ++ src/CreateConventionalCommit.php | 31 + src/Exception/InvalidArgumentException.php | 9 + src/Section/Body.php | 34 + src/Section/Description.php | 49 + src/Section/Footer.php | 34 + src/Section/Scope.php | 55 + src/Section/Subject.php | 59 + src/Section/Type.php | 55 + tests/Unit/CommitCommandTest.php | 87 + tests/Unit/ConfigurationTest.php | 64 + tests/Unit/CreateConventionalCommitTest.php | 56 + tests/Unit/Fixture/configuration.php | 0 tests/Unit/Section/BodyTest.php | 41 + tests/Unit/Section/DescriptionTest.php | 58 + tests/Unit/Section/FooterTest.php | 41 + tests/Unit/Section/ScopeTest.php | 74 + tests/Unit/Section/SubjectTest.php | 100 + tests/Unit/Section/TypeTest.php | 74 + 29 files changed, 3462 insertions(+) create mode 100644 .gitignore create mode 100644 .php-commitizen.php create mode 100644 .scrutinizer.yml create mode 100644 LICENSE create mode 100644 README.md create mode 100644 bin/php-commitizen create mode 100644 composer.json create mode 100644 composer.lock create mode 100644 phpunit.xml create mode 100644 src/CommitCommand.php create mode 100644 src/Configuration.php create mode 100644 src/CreateConventionalCommit.php create mode 100644 src/Exception/InvalidArgumentException.php create mode 100644 src/Section/Body.php create mode 100644 src/Section/Description.php create mode 100644 src/Section/Footer.php create mode 100644 src/Section/Scope.php create mode 100644 src/Section/Subject.php create mode 100644 src/Section/Type.php create mode 100644 tests/Unit/CommitCommandTest.php create mode 100644 tests/Unit/ConfigurationTest.php create mode 100644 tests/Unit/CreateConventionalCommitTest.php create mode 100644 tests/Unit/Fixture/configuration.php create mode 100644 tests/Unit/Section/BodyTest.php create mode 100644 tests/Unit/Section/DescriptionTest.php create mode 100644 tests/Unit/Section/FooterTest.php create mode 100644 tests/Unit/Section/ScopeTest.php create mode 100644 tests/Unit/Section/SubjectTest.php create mode 100644 tests/Unit/Section/TypeTest.php diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..57872d0 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/vendor/ diff --git a/.php-commitizen.php b/.php-commitizen.php new file mode 100644 index 0000000..12ee34f --- /dev/null +++ b/.php-commitizen.php @@ -0,0 +1,30 @@ + [ + 'lengthMin' => 1, + 'lengthMax' => 5, + 'acceptExtra' => false, + 'values' => ['feat', 'fix'], + ], + 'scope' => [ + 'lengthMin' => 0, + 'lengthMax' => 10, + 'acceptExtra' => true, + 'values' => [], + ], + 'description' => [ + 'lengthMin' => 1, + 'lengthMax' => 44, + ], + 'subject' => [ + 'lengthMin' => 1, + 'lengthMax' => 50, + ], + 'body' => [ + 'wrap' => 72, + ], + 'footer' => [ + 'wrap' => 72, + ], +]; \ No newline at end of file diff --git a/.scrutinizer.yml b/.scrutinizer.yml new file mode 100644 index 0000000..a1d9f11 --- /dev/null +++ b/.scrutinizer.yml @@ -0,0 +1,18 @@ +build: + environment: + php: + version: 7.1 + version: 7.2 + tests: + override: + - + command: 'vendor/bin/phpunit --coverage-clover=coverage-file' + coverage: + file: 'coverage-file' + format: 'clover' +checks: + php: + code_rating: true +filter: + excluded_paths: + - "tests/" \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..ee2c87f --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 Damiano Petrungaro + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..02bbc83 --- /dev/null +++ b/README.md @@ -0,0 +1,62 @@ +# PHP Commitizen + +[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/damianopetrungaro/php-commitizen/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/damianopetrungaro/php-commitizen/?branch=master) +[![Code Coverage](https://scrutinizer-ci.com/g/damianopetrungaro/php-commitizen/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/damianopetrungaro/php-commitizen/?branch=master) +[![Build Status](https://scrutinizer-ci.com/g/damianopetrungaro/php-commitizen/badges/build.png?b=master)](https://scrutinizer-ci.com/g/damianopetrungaro/php-commitizen/build-status/master) + +Commitizen is a tool built for create good commits for a clean and readable git history. + +This tool follow the [Conventional Commit specs](https://conventionalcommits.org/) and some best practices described in [this slides](https://slides.com/damianopetrungaro/working-with-git) + +# Installation and usage + +You can install it easily with composer + +`$ php composer.phar require --dev damianopetrungaro/php-commitizen` + +Usage is simple too + +`$ php vendor/bin/php-commitizen commit` + +You can also +- pass a flag for add all the file to the stage: `-a` +- specify a custom configuration file adding the file path as argument + +You can ask for more information using: `$ php vendor/bin/php-commitizen commit --help` + +# Configuration file + +The configuration file must return an array (or partial override) + +``` + [ + 'lengthMin' => 1, // Min length of the type + 'lengthMax' => 5, // Max length of the type + 'acceptExtra' => false, // Allow adding types not listed in 'values' key + 'values' => ['feat', 'fix'], // All the values usable as type + ], + 'scope' => [ + 'lengthMin' => 0, // Min length of the scope + 'lengthMax' => 10, // Max length of the scope + 'acceptExtra' => true, // Allow adding scopes not listed in 'values' key + 'values' => [], // All the values usable as scope + ], + 'description' => [ + 'lengthMin' => 1, // Min length of the description + 'lengthMax' => 44, // Max length of the description + ], + 'subject' => [ + 'lengthMin' => 1, // Min length of the subject + 'lengthMax' => 50, // Max length of the subject + ], + 'body' => [ + 'wrap' => 72, // Wrap the body at 72 characters + ], + 'footer' => [ + 'wrap' => 72, Wrap the footer at 72 characters + ], +]; +``` diff --git a/bin/php-commitizen b/bin/php-commitizen new file mode 100644 index 0000000..667b968 --- /dev/null +++ b/bin/php-commitizen @@ -0,0 +1,24 @@ +#!/usr/bin/env php +add(new \Damianopetrungaro\PHPCommitizen\CommitCommand($configuration, new CreateConventionalCommit())); + $app->run(); +} catch (Throwable $e) { + (new ConsoleOutput())->writeln("{$e->getMessage()}"); +} \ No newline at end of file diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..6c7131a --- /dev/null +++ b/composer.json @@ -0,0 +1,41 @@ +{ + "name": "damianopetrungaro/php-commitizen", + "description": "Help writing Git commit following conventional commit specs", + "keywords": [ + "git", + "commit", + "conventionalcommit", + "conventional commit", + "atomic commit", + "atomic" + ], + "type": "library", + "require": { + "roave/security-advisories": "dev-master", + "symfony/console": "^4.0" + }, + "require-dev": { + "phpunit/phpunit": "^7.0", + "php-mock/php-mock-prophecy": "^0.0.2" + }, + "license": "MIT", + "authors": [ + { + "name": "Damiano Petrungaro", + "email": "damianopetrungaro@gmail.com" + } + ], + "autoload": { + "psr-4": { + "Damianopetrungaro\\PHPCommitizen\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "Damianopetrungaro\\PHPCommitizen\\": "tests/Unit" + } + }, + "bin": [ + "bin/php-commitizen" + ] +} diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..793ffee --- /dev/null +++ b/composer.lock @@ -0,0 +1,1918 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "This file is @generated automatically" + ], + "content-hash": "df9875eff535019a8ba423c8c47a97b3", + "packages": [ + { + "name": "roave/security-advisories", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/Roave/SecurityAdvisories.git", + "reference": "5ebdd35b291cf9be4a425022872cb3aaf03192df" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/5ebdd35b291cf9be4a425022872cb3aaf03192df", + "reference": "5ebdd35b291cf9be4a425022872cb3aaf03192df", + "shasum": "" + }, + "conflict": { + "adodb/adodb-php": "<5.20.6", + "amphp/artax": "<1.0.6|>=2,<2.0.6", + "aws/aws-sdk-php": ">=3,<3.2.1", + "bugsnag/bugsnag-laravel": ">=2,<2.0.2", + "cakephp/cakephp": ">=1.3,<1.3.18|>=2,<2.4.99|>=2.5,<2.5.99|>=2.6,<2.6.12|>=2.7,<2.7.6|>=3,<3.0.15|>=3.1,<3.1.4", + "cart2quote/module-quotation": ">=4.1.6,<=4.4.5|>=5,<5.4.4", + "cartalyst/sentry": "<=2.1.6", + "codeigniter/framework": "<=3.0.6", + "composer/composer": "<=1.0.0-alpha11", + "contao-components/mediaelement": ">=2.14.2,<2.21.1", + "contao/core": ">=2,<3.5.32", + "contao/core-bundle": ">=4,<4.4.8", + "contao/listing-bundle": ">=4,<4.4.8", + "contao/newsletter-bundle": ">=4,<4.1", + "doctrine/annotations": ">=1,<1.2.7", + "doctrine/cache": ">=1,<1.3.2|>=1.4,<1.4.2", + "doctrine/common": ">=2,<2.4.3|>=2.5,<2.5.1", + "doctrine/dbal": ">=2,<2.0.8|>=2.1,<2.1.2", + "doctrine/doctrine-bundle": "<1.5.2", + "doctrine/doctrine-module": "<=0.7.1", + "doctrine/mongodb-odm": ">=1,<1.0.2", + "doctrine/mongodb-odm-bundle": ">=2,<3.0.1", + "doctrine/orm": ">=2,<2.4.8|>=2.5,<2.5.1", + "dompdf/dompdf": ">=0.6,<0.6.2", + "drupal/core": ">=8,<8.3.7", + "drupal/drupal": ">=8,<8.3.7", + "ezsystems/ezpublish-legacy": ">=5.3,<5.3.12.2|>=5.4,<5.4.10.1|>=2017.8,<2017.8.1.1", + "firebase/php-jwt": "<2", + "friendsofsymfony/rest-bundle": ">=1.2,<1.2.2", + "friendsofsymfony/user-bundle": ">=1.2,<1.3.5", + "gree/jose": "<=2.2", + "gregwar/rst": "<1.0.3", + "guzzlehttp/guzzle": ">=6,<6.2.1|>=4.0.0-rc2,<4.2.4|>=5,<5.3.1", + "illuminate/auth": ">=4,<4.0.99|>=4.1,<4.1.26", + "illuminate/database": ">=4,<4.0.99|>=4.1,<4.1.29", + "joomla/session": "<1.3.1", + "laravel/framework": ">=4,<4.0.99|>=4.1,<4.1.29", + "laravel/socialite": ">=1,<1.0.99|>=2,<2.0.10", + "magento/magento1ce": ">=1.5.0.1,<1.9.3.2", + "magento/magento1ee": ">=1.9,<1.14.3.2", + "magento/magento2ce": ">=2,<2.2", + "monolog/monolog": ">=1.8,<1.12", + "namshi/jose": "<2.2", + "onelogin/php-saml": "<2.10.4", + "oro/crm": ">=1.7,<1.7.4", + "oro/platform": ">=1.7,<1.7.4", + "padraic/file_get_contents": "<1.1.2", + "phpmailer/phpmailer": ">=5,<5.2.24", + "phpunit/phpunit": ">=4.8.19,<4.8.28|>=5.0.10,<5.6.3", + "phpxmlrpc/extras": "<0.6.1", + "pusher/pusher-php-server": "<2.2.1", + "sabre/dav": ">=1.6,<1.6.99|>=1.7,<1.7.11|>=1.8,<1.8.9", + "shopware/shopware": "<5.3.7", + "silverstripe/cms": ">=3,<=3.0.11|>=3.1,<3.1.11", + "silverstripe/forum": "<=0.6.1|>=0.7,<=0.7.3", + "silverstripe/framework": ">=3,<3.3", + "silverstripe/userforms": "<3", + "simplesamlphp/saml2": "<1.10.4|>=2,<2.3.5|>=3,<3.1.1", + "simplesamlphp/simplesamlphp": "<1.15.2", + "simplesamlphp/simplesamlphp-module-infocard": "<1.0.1", + "socalnick/scn-social-auth": "<1.15.2", + "squizlabs/php_codesniffer": ">=1,<2.8.1", + "swiftmailer/swiftmailer": ">=4,<5.4.5", + "symfony/dependency-injection": ">=2,<2.0.17", + "symfony/form": ">=2.3,<2.3.35|>=2.4,<2.6.12|>=2.7,<2.7.38|>=2.8,<2.8.31|>=3,<3.2.14|>=3.3,<3.3.13", + "symfony/framework-bundle": ">=2,<2.3.18|>=2.4,<2.4.8|>=2.5,<2.5.2", + "symfony/http-foundation": ">=2,<2.3.27|>=2.4,<2.5.11|>=2.6,<2.6.6", + "symfony/http-kernel": ">=2,<2.3.29|>=2.4,<2.5.12|>=2.6,<2.6.8", + "symfony/intl": ">=2.7,<2.7.38|>=2.8,<2.8.31|>=3,<3.2.14|>=3.3,<3.3.13", + "symfony/routing": ">=2,<2.0.19", + "symfony/security": ">=2,<2.0.25|>=2.1,<2.1.13|>=2.2,<2.2.9|>=2.3,<2.3.37|>=2.4,<2.6.13|>=2.7,<2.7.9|>=2.7.30,<2.7.32|>=2.8.23,<2.8.25|>=3.2.10,<3.2.12|>=3.3.3,<3.3.5", + "symfony/security-core": ">=2.4,<2.6.13|>=2.7,<2.7.9|>=2.7.30,<2.7.32|>=2.8,<2.8.6|>=2.8.23,<2.8.25|>=3,<3.0.6|>=3.2.10,<3.2.12|>=3.3.3,<3.3.5", + "symfony/security-csrf": ">=2.7,<2.7.38|>=2.8,<2.8.31|>=3,<3.2.14|>=3.3,<3.3.13", + "symfony/security-http": ">=2.3,<2.3.41|>=2.4,<2.7.38|>=2.8,<2.8.31|>=3,<3.2.14|>=3.3,<3.3.13", + "symfony/serializer": ">=2,<2.0.11", + "symfony/symfony": ">=2,<2.3.41|>=2.4,<2.7.38|>=2.8,<2.8.31|>=3,<3.2.14|>=3.3,<3.3.13", + "symfony/translation": ">=2,<2.0.17", + "symfony/validator": ">=2,<2.0.24|>=2.1,<2.1.12|>=2.2,<2.2.5|>=2.3,<2.3.3", + "symfony/web-profiler-bundle": ">=2,<2.3.19|>=2.4,<2.4.9|>=2.5,<2.5.4", + "symfony/yaml": ">=2,<2.0.22|>=2.1,<2.1.7", + "thelia/backoffice-default-template": ">=2.1,<2.1.2", + "thelia/thelia": ">=2.1,<2.1.2|>=2.1.0-beta1,<2.1.3", + "twig/twig": "<1.20", + "typo3/cms": ">=6.2,<6.2.30|>=7,<7.6.22|>=8,<8.7.5", + "typo3/flow": ">=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.16|>=3,<3.0.10|>=3.1,<3.1.7|>=3.2,<3.2.7|>=3.3,<3.3.5", + "typo3/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4", + "willdurand/js-translation-bundle": "<2.1.1", + "yiisoft/yii": ">=1.1.14,<1.1.15", + "yiisoft/yii2": "<2.0.5", + "yiisoft/yii2-bootstrap": "<2.0.4", + "yiisoft/yii2-dev": "<2.0.4", + "yiisoft/yii2-gii": "<2.0.4", + "yiisoft/yii2-jui": "<2.0.4", + "zendframework/zend-cache": ">=2.4,<2.4.8|>=2.5,<2.5.3", + "zendframework/zend-captcha": ">=2,<2.4.9|>=2.5,<2.5.2", + "zendframework/zend-crypt": ">=2,<2.4.9|>=2.5,<2.5.2", + "zendframework/zend-db": ">=2,<2.0.99|>=2.1,<2.1.99|>=2.2,<2.2.10|>=2.3,<2.3.5", + "zendframework/zend-diactoros": ">=1,<1.0.4", + "zendframework/zend-form": ">=2,<2.2.7|>=2.3,<2.3.1", + "zendframework/zend-http": ">=2,<2.0.99|>=2.1,<2.1.99|>=2.3,<2.3.8|>=2.4,<2.4.1", + "zendframework/zend-json": ">=2.1,<2.1.6|>=2.2,<2.2.6", + "zendframework/zend-ldap": ">=2,<2.0.99|>=2.1,<2.1.99|>=2.2,<2.2.8|>=2.3,<2.3.3", + "zendframework/zend-mail": ">=2,<2.4.11|>=2.5,<2.7.2", + "zendframework/zend-navigation": ">=2,<2.2.7|>=2.3,<2.3.1", + "zendframework/zend-session": ">=2,<2.0.99|>=2.1,<2.1.99|>=2.2,<2.2.9|>=2.3,<2.3.4", + "zendframework/zend-validator": ">=2.3,<2.3.6", + "zendframework/zend-view": ">=2,<2.2.7|>=2.3,<2.3.1", + "zendframework/zend-xmlrpc": ">=2.1,<2.1.6|>=2.2,<2.2.6", + "zendframework/zendframework": ">=2,<2.4.11|>=2.5,<2.5.1", + "zendframework/zendframework1": "<1.12.20", + "zendframework/zendopenid": ">=2,<2.0.2", + "zendframework/zendxml": ">=1,<1.0.1", + "zetacomponents/mail": "<1.8.2", + "zf-commons/zfc-user": "<1.2.2", + "zfcampus/zf-apigility-doctrine": ">=1,<1.0.3", + "zfr/zfr-oauth2-server-module": "<0.1.2" + }, + "type": "metapackage", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "role": "maintainer" + } + ], + "description": "Prevents installation of composer packages with known security vulnerabilities: no API, simply require it", + "time": "2018-02-13T10:17:11+00:00" + }, + { + "name": "symfony/console", + "version": "v4.0.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "36d5b41e7d4e1ccf0370f6babe966c08ef0a1488" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/36d5b41e7d4e1ccf0370f6babe966c08ef0a1488", + "reference": "36d5b41e7d4e1ccf0370f6babe966c08ef0a1488", + "shasum": "" + }, + "require": { + "php": "^7.1.3", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "symfony/dependency-injection": "<3.4", + "symfony/process": "<3.3" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "~3.4|~4.0", + "symfony/dependency-injection": "~3.4|~4.0", + "symfony/event-dispatcher": "~3.4|~4.0", + "symfony/lock": "~3.4|~4.0", + "symfony/process": "~3.4|~4.0" + }, + "suggest": { + "psr/log": "For using the console logger", + "symfony/event-dispatcher": "", + "symfony/lock": "", + "symfony/process": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Console Component", + "homepage": "https://symfony.com", + "time": "2018-01-29T09:06:29+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.7.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "78be803ce01e55d3491c1397cf1c64beb9c1b63b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/78be803ce01e55d3491c1397cf1c64beb9c1b63b", + "reference": "78be803ce01e55d3491c1397cf1c64beb9c1b63b", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.7-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "time": "2018-01-30T19:27:44+00:00" + } + ], + "packages-dev": [ + { + "name": "doctrine/instantiator", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda", + "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda", + "shasum": "" + }, + "require": { + "php": "^7.1" + }, + "require-dev": { + "athletic/athletic": "~0.1.8", + "ext-pdo": "*", + "ext-phar": "*", + "phpunit/phpunit": "^6.2.3", + "squizlabs/php_codesniffer": "^3.0.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "http://ocramius.github.com/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://github.com/doctrine/instantiator", + "keywords": [ + "constructor", + "instantiate" + ], + "time": "2017-07-22T11:58:36+00:00" + }, + { + "name": "myclabs/deep-copy", + "version": "1.7.0", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e", + "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0" + }, + "require-dev": { + "doctrine/collections": "^1.0", + "doctrine/common": "^2.6", + "phpunit/phpunit": "^4.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + }, + "files": [ + "src/DeepCopy/deep_copy.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "time": "2017-10-19T19:58:43+00:00" + }, + { + "name": "phar-io/manifest", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/manifest.git", + "reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/2df402786ab5368a0169091f61a7c1e0eb6852d0", + "reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-phar": "*", + "phar-io/version": "^1.0.1", + "php": "^5.6 || ^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "time": "2017-03-05T18:14:27+00:00" + }, + { + "name": "phar-io/version", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/version.git", + "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/version/zipball/a70c0ced4be299a63d32fa96d9281d03e94041df", + "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Library for handling version information and constraints", + "time": "2017-03-05T17:38:23+00:00" + }, + { + "name": "php-mock/php-mock", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-mock/php-mock.git", + "reference": "bfa2d17d64dbf129073a7ba2051a96ce52749570" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-mock/php-mock/zipball/bfa2d17d64dbf129073a7ba2051a96ce52749570", + "reference": "bfa2d17d64dbf129073a7ba2051a96ce52749570", + "shasum": "" + }, + "require": { + "php": ">=5.5", + "phpunit/php-text-template": "^1" + }, + "replace": { + "malkusch/php-mock": "*" + }, + "require-dev": { + "phpunit/phpunit": "^4|^5" + }, + "suggest": { + "php-mock/php-mock-mockery": "Allows using PHPMockery for Mockery integration", + "php-mock/php-mock-phpunit": "Allows integration into PHPUnit testcase with the trait PHPMock." + }, + "type": "library", + "autoload": { + "psr-4": { + "phpmock\\": [ + "classes/", + "tests/unit/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "WTFPL" + ], + "authors": [ + { + "name": "Markus Malkusch", + "email": "markus@malkusch.de", + "homepage": "http://markus.malkusch.de", + "role": "Developer" + } + ], + "description": "PHP-Mock can mock built-in PHP functions (e.g. time()). PHP-Mock relies on PHP's namespace fallback policy. No further extension is needed.", + "homepage": "https://github.com/php-mock/php-mock", + "keywords": [ + "BDD", + "TDD", + "function", + "mock", + "stub", + "test", + "test double" + ], + "time": "2015-11-11T22:37:09+00:00" + }, + { + "name": "php-mock/php-mock-integration", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-mock/php-mock-integration.git", + "reference": "e83fb65dd20cd3cf250d554cbd4682b96b684f4b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-mock/php-mock-integration/zipball/e83fb65dd20cd3cf250d554cbd4682b96b684f4b", + "reference": "e83fb65dd20cd3cf250d554cbd4682b96b684f4b", + "shasum": "" + }, + "require": { + "php": ">=5.5", + "php-mock/php-mock": "^1", + "phpunit/php-text-template": "^1" + }, + "require-dev": { + "phpunit/phpunit": "^4|^5" + }, + "type": "library", + "autoload": { + "psr-4": { + "phpmock\\integration\\": "classes/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "WTFPL" + ], + "authors": [ + { + "name": "Markus Malkusch", + "email": "markus@malkusch.de", + "homepage": "http://markus.malkusch.de", + "role": "Developer" + } + ], + "description": "Integration package for PHP-Mock", + "homepage": "https://github.com/php-mock/php-mock-integration", + "keywords": [ + "BDD", + "TDD", + "function", + "mock", + "stub", + "test", + "test double" + ], + "time": "2015-10-26T21:21:42+00:00" + }, + { + "name": "php-mock/php-mock-prophecy", + "version": "0.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-mock/php-mock-prophecy.git", + "reference": "9aaae9952971aedc16daed9f334e65c80f056248" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-mock/php-mock-prophecy/zipball/9aaae9952971aedc16daed9f334e65c80f056248", + "reference": "9aaae9952971aedc16daed9f334e65c80f056248", + "shasum": "" + }, + "require": { + "php": ">=5.5", + "php-mock/php-mock-integration": "^1", + "phpspec/prophecy": "^1" + }, + "require-dev": { + "phpunit/phpunit": "^4|^5" + }, + "type": "library", + "autoload": { + "psr-4": { + "phpmock\\prophecy\\": "classes/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "WTFPL" + ], + "authors": [ + { + "name": "Markus Malkusch", + "email": "markus@malkusch.de", + "homepage": "http://markus.malkusch.de", + "role": "Developer" + } + ], + "description": "Mock built-in PHP functions (e.g. time()) with Prophecy. This package relies on PHP's namespace fallback policy. No further extension is needed.", + "homepage": "https://github.com/php-mock/php-mock-prophecy", + "keywords": [ + "BDD", + "TDD", + "function", + "mock", + "prophecy", + "stub", + "test", + "test double" + ], + "time": "2016-05-13T12:02:19+00:00" + }, + { + "name": "phpdocumentor/reflection-common", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionCommon.git", + "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", + "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", + "shasum": "" + }, + "require": { + "php": ">=5.5" + }, + "require-dev": { + "phpunit/phpunit": "^4.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": [ + "src" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jaap van Otterdijk", + "email": "opensource@ijaap.nl" + } + ], + "description": "Common reflection classes used by phpdocumentor to reflect the code structure", + "homepage": "http://www.phpdoc.org", + "keywords": [ + "FQSEN", + "phpDocumentor", + "phpdoc", + "reflection", + "static analysis" + ], + "time": "2017-09-11T18:02:19+00:00" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "4.3.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "94fd0001232e47129dd3504189fa1c7225010d08" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/94fd0001232e47129dd3504189fa1c7225010d08", + "reference": "94fd0001232e47129dd3504189fa1c7225010d08", + "shasum": "" + }, + "require": { + "php": "^7.0", + "phpdocumentor/reflection-common": "^1.0.0", + "phpdocumentor/type-resolver": "^0.4.0", + "webmozart/assert": "^1.0" + }, + "require-dev": { + "doctrine/instantiator": "~1.0.5", + "mockery/mockery": "^1.0", + "phpunit/phpunit": "^6.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", + "time": "2017-11-30T07:14:17+00:00" + }, + { + "name": "phpdocumentor/type-resolver", + "version": "0.4.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/TypeResolver.git", + "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/9c977708995954784726e25d0cd1dddf4e65b0f7", + "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7", + "shasum": "" + }, + "require": { + "php": "^5.5 || ^7.0", + "phpdocumentor/reflection-common": "^1.0" + }, + "require-dev": { + "mockery/mockery": "^0.9.4", + "phpunit/phpunit": "^5.2||^4.8.24" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "time": "2017-07-14T14:27:02+00:00" + }, + { + "name": "phpspec/prophecy", + "version": "1.7.4", + "source": { + "type": "git", + "url": "https://github.com/phpspec/prophecy.git", + "reference": "9f901e29c93dae4aa77c0bb161df4276f9c9a1be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/9f901e29c93dae4aa77c0bb161df4276f9c9a1be", + "reference": "9f901e29c93dae4aa77c0bb161df4276f9c9a1be", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.2", + "php": "^5.3|^7.0", + "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0", + "sebastian/comparator": "^1.1|^2.0", + "sebastian/recursion-context": "^1.0|^2.0|^3.0" + }, + "require-dev": { + "phpspec/phpspec": "^2.5|^3.2", + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.7.x-dev" + } + }, + "autoload": { + "psr-0": { + "Prophecy\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + }, + { + "name": "Marcello Duarte", + "email": "marcello.duarte@gmail.com" + } + ], + "description": "Highly opinionated mocking framework for PHP 5.3+", + "homepage": "https://github.com/phpspec/prophecy", + "keywords": [ + "Double", + "Dummy", + "fake", + "mock", + "spy", + "stub" + ], + "time": "2018-02-11T18:49:29+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "6.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "f8ca4b604baf23dab89d87773c28cc07405189ba" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/f8ca4b604baf23dab89d87773c28cc07405189ba", + "reference": "f8ca4b604baf23dab89d87773c28cc07405189ba", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-xmlwriter": "*", + "php": "^7.1", + "phpunit/php-file-iterator": "^1.4.2", + "phpunit/php-text-template": "^1.2.1", + "phpunit/php-token-stream": "^3.0", + "sebastian/code-unit-reverse-lookup": "^1.0.1", + "sebastian/environment": "^3.0", + "sebastian/version": "^2.0.1", + "theseer/tokenizer": "^1.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.0" + }, + "suggest": { + "ext-xdebug": "^2.6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "time": "2018-02-02T07:01:41+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "1.4.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/730b01bc3e867237eaac355e06a36b85dd93a8b4", + "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "time": "2017-11-27T13:52:08+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "time": "2015-06-21T13:50:34+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "8b8454ea6958c3dee38453d3bd571e023108c91f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/8b8454ea6958c3dee38453d3bd571e023108c91f", + "reference": "8b8454ea6958c3dee38453d3bd571e023108c91f", + "shasum": "" + }, + "require": { + "php": "^7.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "time": "2018-02-01T13:07:23+00:00" + }, + { + "name": "phpunit/php-token-stream", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-token-stream.git", + "reference": "21ad88bbba7c3d93530d93994e0a33cd45f02ace" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/21ad88bbba7c3d93530d93994e0a33cd45f02ace", + "reference": "21ad88bbba7c3d93530d93994e0a33cd45f02ace", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": "^7.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Wrapper around PHP's tokenizer extension.", + "homepage": "https://github.com/sebastianbergmann/php-token-stream/", + "keywords": [ + "tokenizer" + ], + "time": "2018-02-01T13:16:43+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "7.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "316555dbd0ed4097bbdd17c65ab416bf27a472e9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/316555dbd0ed4097bbdd17c65ab416bf27a472e9", + "reference": "316555dbd0ed4097bbdd17c65ab416bf27a472e9", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "myclabs/deep-copy": "^1.6.1", + "phar-io/manifest": "^1.0.1", + "phar-io/version": "^1.0", + "php": "^7.1", + "phpspec/prophecy": "^1.7", + "phpunit/php-code-coverage": "^6.0", + "phpunit/php-file-iterator": "^1.4.3", + "phpunit/php-text-template": "^1.2.1", + "phpunit/php-timer": "^2.0", + "phpunit/phpunit-mock-objects": "^6.0", + "sebastian/comparator": "^2.1", + "sebastian/diff": "^3.0", + "sebastian/environment": "^3.1", + "sebastian/exporter": "^3.1", + "sebastian/global-state": "^2.0", + "sebastian/object-enumerator": "^3.0.3", + "sebastian/resource-operations": "^1.0", + "sebastian/version": "^2.0.1" + }, + "require-dev": { + "ext-pdo": "*" + }, + "suggest": { + "ext-xdebug": "*", + "phpunit/php-invoker": "^2.0" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "7.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "time": "2018-02-13T06:08:08+00:00" + }, + { + "name": "phpunit/phpunit-mock-objects", + "version": "6.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", + "reference": "e3249dedc2d99259ccae6affbc2684eac37c2e53" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/e3249dedc2d99259ccae6affbc2684eac37c2e53", + "reference": "e3249dedc2d99259ccae6affbc2684eac37c2e53", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.5", + "php": "^7.1", + "phpunit/php-text-template": "^1.2.1", + "sebastian/exporter": "^3.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.0" + }, + "suggest": { + "ext-soap": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Mock Object library for PHPUnit", + "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", + "keywords": [ + "mock", + "xunit" + ], + "time": "2018-02-15T05:27:38+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", + "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.7 || ^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Looks up which function or method a line of code belongs to", + "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "time": "2017-03-04T06:30:41+00:00" + }, + { + "name": "sebastian/comparator", + "version": "2.1.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "34369daee48eafb2651bea869b4b15d75ccc35f9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/34369daee48eafb2651bea869b4b15d75ccc35f9", + "reference": "34369daee48eafb2651bea869b4b15d75ccc35f9", + "shasum": "" + }, + "require": { + "php": "^7.0", + "sebastian/diff": "^2.0 || ^3.0", + "sebastian/exporter": "^3.1" + }, + "require-dev": { + "phpunit/phpunit": "^6.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "https://github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "time": "2018-02-01T13:46:46+00:00" + }, + { + "name": "sebastian/diff", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "e09160918c66281713f1c324c1f4c4c3037ba1e8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/e09160918c66281713f1c324c1f4c4c3037ba1e8", + "reference": "e09160918c66281713f1c324c1f4c4c3037ba1e8", + "shasum": "" + }, + "require": { + "php": "^7.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.0", + "symfony/process": "^2 || ^3.3 || ^4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff", + "udiff", + "unidiff", + "unified diff" + ], + "time": "2018-02-01T13:45:15+00:00" + }, + { + "name": "sebastian/environment", + "version": "3.1.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/cd0871b3975fb7fc44d11314fd1ee20925fce4f5", + "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "time": "2017-07-01T08:51:00+00:00" + }, + { + "name": "sebastian/exporter", + "version": "3.1.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "234199f4528de6d12aaa58b612e98f7d36adb937" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/234199f4528de6d12aaa58b612e98f7d36adb937", + "reference": "234199f4528de6d12aaa58b612e98f7d36adb937", + "shasum": "" + }, + "require": { + "php": "^7.0", + "sebastian/recursion-context": "^3.0" + }, + "require-dev": { + "ext-mbstring": "*", + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "http://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "time": "2017-04-03T13:19:02+00:00" + }, + { + "name": "sebastian/global-state", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", + "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "time": "2017-04-27T15:39:26+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/7cfd9e65d11ffb5af41198476395774d4c8a84c5", + "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5", + "shasum": "" + }, + "require": { + "php": "^7.0", + "sebastian/object-reflector": "^1.1.1", + "sebastian/recursion-context": "^3.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "time": "2017-08-03T12:35:26+00:00" + }, + { + "name": "sebastian/object-reflector", + "version": "1.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "773f97c67f28de00d397be301821b06708fca0be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/773f97c67f28de00d397be301821b06708fca0be", + "reference": "773f97c67f28de00d397be301821b06708fca0be", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "time": "2017-03-29T09:07:27+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", + "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "http://www.github.com/sebastianbergmann/recursion-context", + "time": "2017-03-03T06:23:57+00:00" + }, + { + "name": "sebastian/resource-operations", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/resource-operations.git", + "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", + "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", + "shasum": "" + }, + "require": { + "php": ">=5.6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides a list of PHP built-in functions that operate on resources", + "homepage": "https://www.github.com/sebastianbergmann/resource-operations", + "time": "2015-07-28T20:34:47+00:00" + }, + { + "name": "sebastian/version", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", + "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "time": "2016-10-03T07:35:21+00:00" + }, + { + "name": "theseer/tokenizer", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/theseer/tokenizer.git", + "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/cb2f008f3f05af2893a87208fe6a6c4985483f8b", + "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": "^7.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + } + ], + "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", + "time": "2017-04-07T12:08:54+00:00" + }, + { + "name": "webmozart/assert", + "version": "1.3.0", + "source": { + "type": "git", + "url": "https://github.com/webmozart/assert.git", + "reference": "0df1908962e7a3071564e857d86874dad1ef204a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozart/assert/zipball/0df1908962e7a3071564e857d86874dad1ef204a", + "reference": "0df1908962e7a3071564e857d86874dad1ef204a", + "shasum": "" + }, + "require": { + "php": "^5.3.3 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.6", + "sebastian/version": "^1.0.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\Assert\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Assertions to validate method input/output with nice error messages.", + "keywords": [ + "assert", + "check", + "validate" + ], + "time": "2018-01-29T19:49:41+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": { + "roave/security-advisories": 20 + }, + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [] +} diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..ed698d2 --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,22 @@ + + + + + ./tests/Unit/ + + + + + ./src/ + + + \ No newline at end of file diff --git a/src/CommitCommand.php b/src/CommitCommand.php new file mode 100644 index 0000000..4564b0a --- /dev/null +++ b/src/CommitCommand.php @@ -0,0 +1,203 @@ +configuration = $configuration; + $this->createConventionalCommit = $createConventionalCommit; + $this->questionHelper = $questionHelper ?: new QuestionHelper(); + } + + protected function configure(): void + { + $this->setName(self::COMMAND_NAME); + $this->setDescription(self::COMMAND_DESCRIPTION); + $this->addArgument( + self::ARGUMENT_PATH_TO_CONFIGURATION, + null, + self::ARGUMENT_PATH_TO_CONFIGURATION_DESCRIPTION + ); + $this->addOption( + self::OPTION_ADD_FILE_TO_STAGE_NAME, + self::OPTION_ADD_FILE_TO_STAGE_SHORT_NAME, + null, + self::OPTION_ADD_FILE_TO_STAGE_DESCRIPTION + ); + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + $configuration = $this->loadConfiguration($input->getArgument(self::ARGUMENT_PATH_TO_CONFIGURATION)); + + try { + $type = $this->createType($input, $output, $configuration); + $scope = $this->createScope($input, $output, $configuration); + $description = $this->createDescription($input, $output, $configuration); + $subject = Subject::build($type, $scope, $description, $configuration); + $body = $this->createBody($input, $output, $configuration); + $footer = $this->createFooter($input, $output, $configuration); + $addAll = $input->getOption(self::OPTION_ADD_FILE_TO_STAGE_NAME); + ($this->createConventionalCommit)($subject, $body, $footer, $addAll); + } catch (InvalidArgumentException $e) { + $output->writeln("{$e->getMessage()}"); + } + } + + private function loadConfiguration(?string $customConfigurationPath): Configuration + { + if ($customConfigurationPath === null) { + return Configuration::fromArray($this->configuration); + } + + if (!file_exists($customConfigurationPath)) { + throw new InvalidArgumentException("Custom configuration file does not exists: '$customConfigurationPath'"); + } + + $customConfiguration = require $customConfigurationPath; + + if (!is_array($customConfiguration)) { + throw new InvalidArgumentException('Custom configuration file must return an array'); + } + + return Configuration::fromArray(array_merge($this->configuration, $customConfiguration)); + } + + private function createType(InputInterface $input, OutputInterface $output, Configuration $configuration): Type + { + $output->writeln('Commits MUST be prefixed with a type, which consists of a noun, feat, fix, etc.'); + $output->writeln("Type length must be between {$configuration->minLengthType()} and {$configuration->maxLengthType()}"); + + $typeValues = $configuration->types(); + if ($configuration->acceptExtraType() === true) { + $typeValues[] = self::EXTRA_KEY_NAME; + } + + if ($typeValues !== [self::EXTRA_KEY_NAME]) { + $choice = new ChoiceQuestion("Select commit's type:", $typeValues); + $typeInput = $this->questionHelper->ask($input, $output, $choice); + } + + if (!isset($typeInput) || $typeInput === self::EXTRA_KEY_NAME) { + $question = new Question("Enter a custom commit's type:", ''); + $typeInput = $this->questionHelper->ask($input, $output, $question); + } + + return Type::build($typeInput, $configuration); + } + + private function createScope(InputInterface $input, OutputInterface $output, Configuration $configuration): ?Scope + { + $scopeValues = $configuration->scopes(); + if ($scopeValues === [] && $configuration->acceptExtraScope() === false) { + return null; + } + + $output->writeln('An optional scope MAY be provided after a type. A scope is a phrase describing a section of the codebase.'); + $output->writeln("Scope length MUST be between {$configuration->minLengthScope()} and {$configuration->maxLengthScope()}"); + + if ($configuration->acceptExtraScope() === true) { + $scopeValues[] = self::EXTRA_KEY_NAME; + } + + if ($scopeValues !== [self::EXTRA_KEY_NAME] && $scopeValues !== []) { + $choice = new ChoiceQuestion("Select commit's scope:", $scopeValues); + $scopeInput = $this->questionHelper->ask($input, $output, $choice); + } + + if (!isset($scopeInput) || $scopeInput === self::EXTRA_KEY_NAME) { + $question = new Question("Enter a custom commit's scope:", ''); + $scopeInput = $this->questionHelper->ask($input, $output, $question); + } + + if ($scopeInput === '') { + + return null; + } + + return Scope::build($scopeInput, $configuration); + } + + private function createDescription(InputInterface $input, OutputInterface $output, Configuration $configuration): Description + { + $output->writeln('A description MUST immediately follow the type/scope prefix. The description is a short description of the changes'); + $output->writeln("Description length MUST be between {$configuration->minLengthDescription()} and {$configuration->maxLengthDescription()}"); + + $question = new Question("Enter a custom commit's description:", ''); + $descriptionInput = $this->questionHelper->ask($input, $output, $question); + return Description::build($descriptionInput, $configuration); + } + + private function createBody(InputInterface $input, OutputInterface $output, Configuration $configuration): Body + { + $output->writeln('A longer commit body MAY be provided after the short description.'); + + $question = new Question("Enter commit's body:", ''); + $bodyInput = $this->questionHelper->ask($input, $output, $question); + return Body::build($bodyInput, $configuration); + } + + private function createFooter(InputInterface $input, OutputInterface $output, Configuration $configuration): Footer + { + $output->writeln('A footer MAY be provided one blank line after the body. The footer SHOULD contain additional meta-information about the changes(such as the issues it fixes, e.g., fixes #13, #5).'); + + $question = new Question("Enter commit's footer:", ''); + $footerInput = $this->questionHelper->ask($input, $output, $question); + return Footer::build($footerInput, $configuration); + } +} \ No newline at end of file diff --git a/src/Configuration.php b/src/Configuration.php new file mode 100644 index 0000000..fb50fd3 --- /dev/null +++ b/src/Configuration.php @@ -0,0 +1,201 @@ +minLengthType = $minLengthType; + $this->maxLengthType = $maxLengthType; + $this->acceptExtraType = $acceptExtraType; + $this->types = $types; + $this->minLengthScope = $minLengthScope; + $this->maxLengthScope = $maxLengthScope; + $this->acceptExtraScope = $acceptExtraScope; + $this->scopes = $scopes; + $this->minLengthDescription = $minLengthDescription; + $this->maxLengthDescription = $maxLengthDescription; + $this->minLengthSubject = $minLengthSubject; + $this->maxLengthSubject = $maxLengthSubject; + $this->wrapWidthBody = $wrapWidthBody; + $this->wrapWidthFooter = $wrapWidthFooter; + } + + public static function fromArray(array $configuration): self + { + return new self( + $configuration['type']['lengthMin'], + $configuration['type']['lengthMax'], + $configuration['type']['acceptExtra'], + $configuration['type']['values'], + $configuration['scope']['lengthMin'], + $configuration['scope']['lengthMax'], + $configuration['scope']['acceptExtra'], + $configuration['scope']['values'], + $configuration['description']['lengthMin'], + $configuration['description']['lengthMax'], + $configuration['subject']['lengthMin'], + $configuration['subject']['lengthMax'], + $configuration['body']['wrap'], + $configuration['footer']['wrap'] + ); + } + + public function minLengthType(): int + { + return $this->minLengthType; + } + + public function maxLengthType(): int + { + return $this->maxLengthType; + } + + public function acceptExtraType(): bool + { + return $this->acceptExtraType; + } + + public function types(): array + { + return $this->types; + } + + public function minLengthScope(): int + { + return $this->minLengthScope; + } + + public function maxLengthScope(): int + { + return $this->maxLengthScope; + } + + public function acceptExtraScope(): bool + { + return $this->acceptExtraScope; + } + + public function scopes(): array + { + return $this->scopes; + } + + public function minLengthDescription(): int + { + return $this->minLengthDescription; + } + + public function maxLengthDescription(): int + { + return $this->maxLengthDescription; + } + + public function minLengthSubject(): int + { + return $this->minLengthSubject; + } + + public function maxLengthSubject(): int + { + return $this->maxLengthSubject; + } + + public function wrapWidthBody(): int + { + return $this->wrapWidthBody; + } + + public function wrapWidthFooter(): int + { + return $this->wrapWidthFooter; + } +} \ No newline at end of file diff --git a/src/CreateConventionalCommit.php b/src/CreateConventionalCommit.php new file mode 100644 index 0000000..32e0933 --- /dev/null +++ b/src/CreateConventionalCommit.php @@ -0,0 +1,31 @@ +exec('git add .'); + } + + $safeSubject = escapeshellarg((string)$subject); + $safeBody = escapeshellarg((string)$body); + $safeFooter = escapeshellarg((string)$footer); + $this->exec("git commit -m $safeSubject -m $safeBody -m $safeFooter"); + } + + protected function exec(string $command): void + { + exec($command); + } +} \ No newline at end of file diff --git a/src/Exception/InvalidArgumentException.php b/src/Exception/InvalidArgumentException.php new file mode 100644 index 0000000..86436f3 --- /dev/null +++ b/src/Exception/InvalidArgumentException.php @@ -0,0 +1,9 @@ +body = $body; + } + + public static function build(string $body, Configuration $configuration): self + { + $body = trim($body); + $body = wordwrap($body, $configuration->wrapWidthBody(), PHP_EOL, true); + + return new self($body); + } + + public function __toString(): string + { + return $this->body; + } +} \ No newline at end of file diff --git a/src/Section/Description.php b/src/Section/Description.php new file mode 100644 index 0000000..dff583e --- /dev/null +++ b/src/Section/Description.php @@ -0,0 +1,49 @@ +description = $description; + } + + /** + * @throws InvalidArgumentException + */ + public static function build(string $description, Configuration $configuration): self + { + $description = trim($description); + $descriptionLength = strlen($description); + + if ($descriptionLength > $configuration->maxLengthDescription() || + $descriptionLength < $configuration->minLengthDescription() + ) { + $errorMessage = sprintf("Invalid length for description: '%s'. Must be between %s and %s", + $description, + $configuration->minLengthDescription(), + $configuration->maxLengthDescription() + ); + throw new InvalidArgumentException($errorMessage); + } + + return new self($description); + } + + public function __toString(): string + { + return $this->description; + } +} \ No newline at end of file diff --git a/src/Section/Footer.php b/src/Section/Footer.php new file mode 100644 index 0000000..562ab62 --- /dev/null +++ b/src/Section/Footer.php @@ -0,0 +1,34 @@ +footer = $footer; + } + + public static function build(string $footer, Configuration $configuration): self + { + $footer = trim($footer); + $footer = wordwrap($footer, $configuration->wrapWidthFooter(), PHP_EOL, true); + + return new self($footer); + } + + public function __toString(): string + { + return $this->footer; + } +} \ No newline at end of file diff --git a/src/Section/Scope.php b/src/Section/Scope.php new file mode 100644 index 0000000..c963e75 --- /dev/null +++ b/src/Section/Scope.php @@ -0,0 +1,55 @@ +scope = $scope; + } + + /** + * @throws InvalidArgumentException + */ + public static function build(string $scope, Configuration $configuration): self + { + $scope = trim($scope); + $scopeLength = strlen($scope); + + if ($scopeLength > $configuration->maxLengthScope() || $scopeLength < $configuration->minLengthScope()) { + $errorMessage = sprintf("Invalid length for scope: '%s'. Must be between %s and %s", + $scope, + $configuration->minLengthScope(), + $configuration->maxLengthScope() + ); + throw new InvalidArgumentException($errorMessage); + } + + if (!$configuration->acceptExtraScope() && !in_array($scope, $configuration->scopes(), true)) { + $validScopes = implode(', ', $configuration->scopes()); + throw new InvalidArgumentException("Invalid scope: '$scope'. Valid scopes are: [$validScopes]"); + } + + + return new self($scope); + } + + public function __toString(): string + { + return "($this->scope)"; + } +} \ No newline at end of file diff --git a/src/Section/Subject.php b/src/Section/Subject.php new file mode 100644 index 0000000..0bcc640 --- /dev/null +++ b/src/Section/Subject.php @@ -0,0 +1,59 @@ +type = $type; + $this->scope = $scope; + $this->description = $description; + } + + /** + * @throws InvalidArgumentException + */ + public static function build(Type $type, ?Scope $scope, Description $description, Configuration $configuration): self + { + // 2 char more needed for the ": " when transforming to string + $subjectLength = strlen((string)$type) + strlen((string)$scope) + strlen((string)$description) + 2; + + if ($subjectLength > $configuration->maxLengthSubject() || $subjectLength < $configuration->minLengthSubject()) { + $errorMessage = sprintf("Invalid length for subject: '%s'. Must be between %s and %s", + "{$type}{$scope}: {$description}", + $configuration->minLengthSubject(), + $configuration->maxLengthSubject() + ); + throw new InvalidArgumentException($errorMessage); + } + + return new self($type, $scope, $description); + } + + public function __toString(): string + { + return "{$this->type}{$this->scope}: {$this->description}"; + } +} \ No newline at end of file diff --git a/src/Section/Type.php b/src/Section/Type.php new file mode 100644 index 0000000..4a711bd --- /dev/null +++ b/src/Section/Type.php @@ -0,0 +1,55 @@ +type = $type; + } + + /** + * @throws InvalidArgumentException + */ + public static function build(string $type, Configuration $configuration): self + { + $type = trim($type); + $typeLength = strlen($type); + + if ($typeLength > $configuration->maxLengthType() || $typeLength < $configuration->minLengthType()) { + $errorMessage = sprintf("Invalid length for type: '%s'. Must be between %s and %s", + $type, + $configuration->minLengthType(), + $configuration->maxLengthType() + ); + throw new InvalidArgumentException($errorMessage); + } + + if (!$configuration->acceptExtraType() && !in_array($type, $configuration->types(), true)) { + $validTypes = implode(', ', $configuration->types()); + throw new InvalidArgumentException("Invalid type: '$type'. Valid types are: [$validTypes]"); + } + + return new self($type); + } + + public function __toString(): string + { + return $this->type; + } +} \ No newline at end of file diff --git a/tests/Unit/CommitCommandTest.php b/tests/Unit/CommitCommandTest.php new file mode 100644 index 0000000..ae50abd --- /dev/null +++ b/tests/Unit/CommitCommandTest.php @@ -0,0 +1,87 @@ +expectException(InvalidArgumentException::class); + $this->expectExceptionMessage("Custom configuration file does not exists: 'not_existing_file.php'"); + $configuration = require __DIR__ . '/../../.php-commitizen.php'; + $app = new Application('PHP Commitizen'); + $app->add(new CommitCommand($configuration, new CreateConventionalCommit())); + + $command = $app->find('commit'); + $commandTester = new CommandTester($command); + $commandTester->execute([ + 'command' => $command->getName(), + 'config' => 'not_existing_file.php' + ]); + } + + public function testCustomConfigurationFileDoesNotReturnAnArray(): void + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Custom configuration file must return an array'); + $configuration = require __DIR__ . '/../../.php-commitizen.php'; + $app = new Application('PHP Commitizen'); + $app->add(new CommitCommand($configuration, new CreateConventionalCommit())); + $command = $app->find('commit'); + $commandTester = new CommandTester($command); + $commandTester->execute([ + 'command' => $command->getName(), + 'config' => __DIR__ . '/../../tests/Unit/Fixture/configuration.php', + ]); + } + + public function testCustomConfigurationIsMerged(): void + { + $that = $this; + $createConventionalCommitProphecy = $this->prophesize(CreateConventionalCommit::class); + $createConventionalCommitProphecy + ->__invoke( + Argument::type(Subject::class), + Argument::type(Body::class), + Argument::type(Footer::class), + false + ) + ->shouldBeCalledTimes(1) + ->will(function (array $data) use ($that) { + [$subject, $body, $footer, $addAllToStage] = $data; + $that->assertSame('fix(scope): commit description', (string)$subject); + $that->assertSame('commit body', (string)$body); + $that->assertSame('commit footer', (string)$footer); + $that->assertFalse($addAllToStage); + }); + + $commitCommand = new CommitCommand([], $createConventionalCommitProphecy->reveal()); + $app = new Application('PHP Commitizen'); + $app->add($commitCommand); + + $command = $app->find('commit'); + $commandTester = new CommandTester($command); + $commandTester->setInputs([ + 'fix', + 'scope', + 'commit description', + 'commit body', + 'commit footer', + ]); + $commandTester->execute([ + 'command' => $command->getName(), + 'config' => '.php-commitizen.php' + ]); + } +} \ No newline at end of file diff --git a/tests/Unit/ConfigurationTest.php b/tests/Unit/ConfigurationTest.php new file mode 100644 index 0000000..96f66d3 --- /dev/null +++ b/tests/Unit/ConfigurationTest.php @@ -0,0 +1,64 @@ +assertSame($configuration->minLengthType(), $config['type']['lengthMin']); + $this->assertSame($configuration->maxLengthType(), $config['type']['lengthMax']); + $this->assertSame($configuration->acceptExtraType(), $config['type']['acceptExtra']); + $this->assertSame($configuration->types(), $config['type']['values']); + $this->assertSame($configuration->minLengthScope(), $config['scope']['lengthMin']); + $this->assertSame($configuration->maxLengthScope(), $config['scope']['lengthMax']); + $this->assertSame($configuration->acceptExtraScope(), $config['scope']['acceptExtra']); + $this->assertSame($configuration->scopes(), $config['scope']['values']); + $this->assertSame($configuration->minLengthDescription(), $config['description']['lengthMin']); + $this->assertSame($configuration->maxLengthDescription(), $config['description']['lengthMax']); + $this->assertSame($configuration->minLengthSubject(), $config['subject']['lengthMin']); + $this->assertSame($configuration->maxLengthSubject(), $config['subject']['lengthMax']); + $this->assertSame($configuration->wrapWidthBody(), $config['body']['wrap']); + $this->assertSame($configuration->wrapWidthFooter(), $config['footer']['wrap']); + } + + public function configurationDataProvider(): array + { + return [[[ + 'type' => [ + 'lengthMin' => 1, + 'lengthMax' => 5, + 'acceptExtra' => false, + 'values' => ['feat', 'fix'], + ], + 'scope' => [ + 'lengthMin' => 0, + 'lengthMax' => 10, + 'acceptExtra' => true, + 'values' => [], + ], + 'description' => [ + 'lengthMin' => 1, + 'lengthMax' => 44, + ], + 'subject' => [ + 'lengthMin' => 1, + 'lengthMax' => 50, + ], + 'body' => [ + 'wrap' => 72, + ], + 'footer' => [ + 'wrap' => 72, + ], + ]]]; + } +} \ No newline at end of file diff --git a/tests/Unit/CreateConventionalCommitTest.php b/tests/Unit/CreateConventionalCommitTest.php new file mode 100644 index 0000000..6925b01 --- /dev/null +++ b/tests/Unit/CreateConventionalCommitTest.php @@ -0,0 +1,56 @@ +createPartialMock(CreateConventionalCommit::class, ['exec']); + $createConventionalCommit + ->expects($this->once()) + ->method('exec') + ->with($this->equalTo("git commit -m 'subject' -m 'body' -m 'footer'")); + + $subjectProphecy = $this->prophesize(Subject::class); + $subjectProphecy->__toString()->shouldBeCalled()->willReturn('subject'); + + $bodyProphecy = $this->prophesize(Body::class); + $bodyProphecy->__toString()->shouldBeCalled()->willReturn('body'); + + $footerProphecy = $this->prophesize(Footer::class); + $footerProphecy->__toString()->shouldBeCalled()->willReturn('footer'); + + $createConventionalCommit($subjectProphecy->reveal(), $bodyProphecy->reveal(), $footerProphecy->reveal(), false); + } + + public function testCreateConventionalCommitWithAddAllFlag(): void + { + $createConventionalCommit = $this->createPartialMock(CreateConventionalCommit::class, ['exec']); + $createConventionalCommit + ->expects($this->exactly(2)) + ->method('exec') + ->withConsecutive( + [$this->equalTo('git add .')], + [$this->equalTo("git commit -m 'subject' -m 'body' -m 'footer'")] + ); + + $subjectProphecy = $this->prophesize(Subject::class); + $subjectProphecy->__toString()->shouldBeCalled()->willReturn('subject'); + + $bodyProphecy = $this->prophesize(Body::class); + $bodyProphecy->__toString()->shouldBeCalled()->willReturn('body'); + + $footerProphecy = $this->prophesize(Footer::class); + $footerProphecy->__toString()->shouldBeCalled()->willReturn('footer'); + + $createConventionalCommit($subjectProphecy->reveal(), $bodyProphecy->reveal(), $footerProphecy->reveal(), true); + } +} \ No newline at end of file diff --git a/tests/Unit/Fixture/configuration.php b/tests/Unit/Fixture/configuration.php new file mode 100644 index 0000000..e69de29 diff --git a/tests/Unit/Section/BodyTest.php b/tests/Unit/Section/BodyTest.php new file mode 100644 index 0000000..7e84be7 --- /dev/null +++ b/tests/Unit/Section/BodyTest.php @@ -0,0 +1,41 @@ +prophesize(Configuration::class); + $configurationProphecy->wrapWidthBody()->willReturn(72); + + $body = Body::build($actual, $configurationProphecy->reveal()); + $this->assertSame($expected, $body->__toString()); + } + + public function bodyDataProvider(): array + { + return [ + ['body', 'body'], + [' trim me ', 'trim me'], + [ + '3FiHRUhcIzAOmvReAY4senqnGqzff7gDZSsStJMhd0TBxcrmNmZqhlQFAfOrsryWvlnRydMMqXgbzSuY5OqrDOyUjz', + "3FiHRUhcIzAOmvReAY4senqnGqzff7gDZSsStJMhd0TBxcrmNmZqhlQFAfOrsryWvlnRydMM\nqXgbzSuY5OqrDOyUjz", + ], [ + "+駰#ò;,:._-|\\!\"£$%&/()=?^1234567890ì<>+駰#ò;,:._-|\\!\"£$%&/()=?^1234567890ì<>", + "+駰#ò;,:._-|\\!\"£$%&/()=?^1234567890ì<>+駰#ò;,:._-|\\!\"£$%&/(\n)=?^1234567890ì<>", + ],[ + "3FiHRUhcIzAOm\nvReAY4senqnGqzff7gDZSsStJMhd0TBxcrmNmZqhlQFAfOrsryWvlnRydMMqXgbzSuY5OqrDOyUjz3FiHRUhc", + "3FiHRUhcIzAOm\nvReAY4senqnGqzff7gDZSsStJMhd0TBxcrmNmZqhlQFAfOrsryWvlnRydMMqXgbzSuY5OqrD\nOyUjz3FiHRUhc", + ], + ]; + } +} \ No newline at end of file diff --git a/tests/Unit/Section/DescriptionTest.php b/tests/Unit/Section/DescriptionTest.php new file mode 100644 index 0000000..671a86a --- /dev/null +++ b/tests/Unit/Section/DescriptionTest.php @@ -0,0 +1,58 @@ +prophesize(Configuration::class); + $configurationProphecy->maxLengthDescription()->willReturn($maxLength); + $configurationProphecy->minLengthDescription()->willReturn($minLength); + + $description = Description::build($actual, $configurationProphecy->reveal()); + $this->assertSame($expected, $description->__toString()); + } + + /** + * @dataProvider invalidDescriptionDataProvider + */ + public function testDescriptionFail(string $actual, string $expected, int $minLength, int $maxLength): void + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage("Invalid length for description: '$expected'. Must be between $minLength and $maxLength"); + $configurationProphecy = $this->prophesize(Configuration::class); + $configurationProphecy->maxLengthDescription()->willReturn($maxLength); + $configurationProphecy->minLengthDescription()->willReturn($minLength); + + Description::build($actual, $configurationProphecy->reveal()); + } + + public function invalidDescriptionDataProvider(): array + { + return [ + ['description', 'description', 1, 4], + [' trim me ', 'trim me', 0, 3], + ['', '', 1, 100], + ]; + } + + public function descriptionDataProvider(): array + { + return [ + ['description', 'description', 1, 15], + [' trim me ', 'trim me', 0, 7], + ['|!"£$%&/()=?^Pé*ç°§;:_', '|!"£$%&/()=?^Pé*ç°§;:_', 0, 1000], + ['', '', 0, 0], + ]; + } +} \ No newline at end of file diff --git a/tests/Unit/Section/FooterTest.php b/tests/Unit/Section/FooterTest.php new file mode 100644 index 0000000..3677950 --- /dev/null +++ b/tests/Unit/Section/FooterTest.php @@ -0,0 +1,41 @@ +prophesize(Configuration::class); + $configurationProphecy->wrapWidthFooter()->willReturn(72); + + $footer = Footer::build($actual, $configurationProphecy->reveal()); + $this->assertSame($expected, $footer->__toString()); + } + + public function footerDataProvider(): array + { + return [ + ['footer', 'footer'], + [' trim me ', 'trim me'], + [ + '3FiHRUhcIzAOmvReAY4senqnGqzff7gDZSsStJMhd0TBxcrmNmZqhlQFAfOrsryWvlnRydMMqXgbzSuY5OqrDOyUjz', + "3FiHRUhcIzAOmvReAY4senqnGqzff7gDZSsStJMhd0TBxcrmNmZqhlQFAfOrsryWvlnRydMM\nqXgbzSuY5OqrDOyUjz", + ], [ + "+駰#ò;,:._-|\\!\"£$%&/()=?^1234567890ì<>+駰#ò;,:._-|\\!\"£$%&/()=?^1234567890ì<>", + "+駰#ò;,:._-|\\!\"£$%&/()=?^1234567890ì<>+駰#ò;,:._-|\\!\"£$%&/(\n)=?^1234567890ì<>", + ], [ + "3FiHRUhcIzAOm\nvReAY4senqnGqzff7gDZSsStJMhd0TBxcrmNmZqhlQFAfOrsryWvlnRydMMqXgbzSuY5OqrDOyUjz3FiHRUhc", + "3FiHRUhcIzAOm\nvReAY4senqnGqzff7gDZSsStJMhd0TBxcrmNmZqhlQFAfOrsryWvlnRydMMqXgbzSuY5OqrD\nOyUjz3FiHRUhc", + ], + ]; + } +} \ No newline at end of file diff --git a/tests/Unit/Section/ScopeTest.php b/tests/Unit/Section/ScopeTest.php new file mode 100644 index 0000000..657b243 --- /dev/null +++ b/tests/Unit/Section/ScopeTest.php @@ -0,0 +1,74 @@ +prophesize(Configuration::class); + $configurationProphecy->maxLengthScope()->willReturn($maxLength); + $configurationProphecy->minLengthScope()->willReturn($minLength); + $configurationProphecy->acceptExtraScope()->willReturn($acceptExtraScope); + $configurationProphecy->scopes()->willReturn($allowedScopes); + + $scope = Scope::build($actual, $configurationProphecy->reveal()); + $this->assertSame($expected, $scope->__toString()); + } + + /** + * @dataProvider invalidScopeDataProvider + */ + public function testScopeFail( + string $actual, + string $errorMessage, + int $minLength, + int $maxLength, + bool $acceptExtraScope, + array $allowedScopes + ): void + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage($errorMessage); + $configurationProphecy = $this->prophesize(Configuration::class); + $configurationProphecy->maxLengthScope()->willReturn($maxLength); + $configurationProphecy->minLengthScope()->willReturn($minLength); + $configurationProphecy->acceptExtraScope()->willReturn($acceptExtraScope); + $configurationProphecy->scopes()->willReturn($allowedScopes); + + Scope::build($actual, $configurationProphecy->reveal()); + } + + public function invalidScopeDataProvider(): array + { + return [ + ['not in list', "Invalid scope: 'not in list'. Valid scopes are: [a, b]", 0, 100, false, ['a', 'b']], + [' too long ', "Invalid length for scope: 'too long'. Must be between 0 and 1", 0, 1, false, []], + ['too short ', "Invalid length for scope: 'too short'. Must be between 35 and 100", 35, 100, false, []], + ]; + } + + public function scopeDataProvider(): array + { + return [ + ['not in list ', '(not in list)', 0, 12, true, ['a', 'b']], + ['a', '(a)', 1, 12, false, ['a', 'b']], + ]; + } +} \ No newline at end of file diff --git a/tests/Unit/Section/SubjectTest.php b/tests/Unit/Section/SubjectTest.php new file mode 100644 index 0000000..17768e8 --- /dev/null +++ b/tests/Unit/Section/SubjectTest.php @@ -0,0 +1,100 @@ +prophesize(Configuration::class); + $configurationProphecy->maxLengthSubject()->willReturn($maxLength); + $configurationProphecy->minLengthSubject()->willReturn($minLength); + + $typeProphecy = $this->prophesize(Type::class); + $typeProphecy->__toString()->willReturn($type); + + $scopeProphecy = $this->prophesize(Scope::class); + $scopeProphecy->__toString()->willReturn($scope); + + $descriptionProphecy = $this->prophesize(Description::class); + $descriptionProphecy->__toString()->willReturn($description); + + $subject = Subject::build( + $typeProphecy->reveal(), + $scopeProphecy->reveal(), + $descriptionProphecy->reveal(), + $configurationProphecy->reveal() + ); + + $this->assertSame($expected, $subject->__toString()); + } + + /** + * @dataProvider invalidSubjectDataProvider + */ + public function testSubjectFail( + string $type, + string $scope, + string $description, + string $errorMessage, + int $minLength, + int $maxLength + ): void + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage($errorMessage); + $configurationProphecy = $this->prophesize(Configuration::class); + $configurationProphecy->maxLengthSubject()->willReturn($maxLength); + $configurationProphecy->minLengthSubject()->willReturn($minLength); + + $typeProphecy = $this->prophesize(Type::class); + $typeProphecy->__toString()->willReturn($type); + + $scopeProphecy = $this->prophesize(Scope::class); + $scopeProphecy->__toString()->willReturn($scope); + + $descriptionProphecy = $this->prophesize(Description::class); + $descriptionProphecy->__toString()->willReturn($description); + + Subject::build( + $typeProphecy->reveal(), + $scopeProphecy->reveal(), + $descriptionProphecy->reveal(), + $configurationProphecy->reveal() + ); + } + + public function invalidSubjectDataProvider(): array + { + return [ + ['subject', '(scope)', 'description', "Invalid length for subject: 'subject(scope): description'. Must be between 0 and 21", 0, 21], + ['subject', '', 'description', "Invalid length for subject: 'subject: description'. Must be between 0 and 5", 0, 5], + ['s', '(s)', 'd', "Invalid length for subject: 's(s): d'. Must be between 0 and 6", 0, 6], + ['s', '(s)', 'd', "Invalid length for subject: 's(s): d'. Must be between 8 and 10", 8, 10], + ]; + } + + public function subjectDataProvider(): array + { + return [ + ['subject', '(scope)', 'description', 'subject(scope): description', 20, 30], + ['s', '', 'd', 's: d', 4, 10], + ]; + } +} \ No newline at end of file diff --git a/tests/Unit/Section/TypeTest.php b/tests/Unit/Section/TypeTest.php new file mode 100644 index 0000000..d50754a --- /dev/null +++ b/tests/Unit/Section/TypeTest.php @@ -0,0 +1,74 @@ +prophesize(Configuration::class); + $configurationProphecy->maxLengthType()->willReturn($maxLength); + $configurationProphecy->minLengthType()->willReturn($minLength); + $configurationProphecy->acceptExtraType()->willReturn($acceptExtraType); + $configurationProphecy->types()->willReturn($allowedTypes); + + $type = Type::build($actual, $configurationProphecy->reveal()); + $this->assertSame($expected, $type->__toString()); + } + + /** + * @dataProvider invalidTypeDataProvider + */ + public function testTypeFail( + string $actual, + string $errorMessage, + int $minLength, + int $maxLength, + bool $acceptExtraType, + array $allowedTypes + ): void + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage($errorMessage); + $configurationProphecy = $this->prophesize(Configuration::class); + $configurationProphecy->maxLengthType()->willReturn($maxLength); + $configurationProphecy->minLengthType()->willReturn($minLength); + $configurationProphecy->acceptExtraType()->willReturn($acceptExtraType); + $configurationProphecy->types()->willReturn($allowedTypes); + + Type::build($actual, $configurationProphecy->reveal()); + } + + public function invalidTypeDataProvider(): array + { + return [ + ['not in list', "Invalid type: 'not in list'. Valid types are: [a, b]", 0, 100, false, ['a', 'b']], + [' too long ', "Invalid length for type: 'too long'. Must be between 0 and 1", 0, 1, false, []], + ['too short ', "Invalid length for type: 'too short'. Must be between 35 and 100", 35, 100, false, []], + ]; + } + + public function typeDataProvider(): array + { + return [ + ['not in list ', 'not in list', 0, 12, true, ['a', 'b']], + ['a', 'a', 1, 12, false, ['a', 'b']], + ]; + } +} \ No newline at end of file