├── .codeclimate.yml ├── .gitignore ├── .scrutinizer.yml ├── .travis.yml ├── CHANGELOG.md ├── CNAME ├── LICENSE.md ├── README.md ├── composer.json ├── env-diff ├── phpunit.xml.dist ├── src ├── Composer │ └── ScriptHandler.php ├── Config.php ├── Console │ ├── Application.php │ └── Command │ │ ├── AbstractCommand.php │ │ ├── ActualizeCommand.php │ │ └── DiffCommand.php ├── Env.php ├── Env │ ├── Dumper.php │ └── Parser.php ├── IO │ ├── ComposerIO.php │ ├── ConsoleIO.php │ └── IOInterface.php └── Processor.php └── tests ├── Composer └── ScriptHandlerTest.php ├── ConfigTest.php ├── Console ├── ApplicationTest.php └── Command │ └── CommandsTest.php ├── ProcessorTest.php └── fixtures ├── actualize ├── delete-old-variable │ ├── .env │ ├── .env.dist │ └── .expected ├── invalid │ ├── dist-not-found │ │ └── error.txt │ ├── invalid-delimiter │ │ ├── .env.dist │ │ └── error.txt │ └── invalid-string │ │ ├── .env.dist │ │ └── error.txt ├── subdirectory │ ├── .expected │ └── sub │ │ └── .env.dist └── valid │ ├── append-new-variable │ ├── .env │ ├── .env.dist │ └── .expected │ ├── create-new-env-file │ ├── .env.dist │ └── .expected │ ├── do-not-delete-old-variable │ ├── .env │ ├── .env.dist │ └── .expected │ ├── do-not-replace-old-variable │ ├── .env │ ├── .env.dist │ └── .expected │ ├── remove-comments │ ├── .env │ ├── .env.dist │ └── .expected │ └── trim-spaces │ ├── .env │ ├── .env.dist │ └── .expected └── difference ├── invalid ├── dist-not-found │ └── error.txt ├── invalid-delimiter │ ├── .env.dist │ └── error.txt ├── invalid-string │ ├── .env.dist │ └── error.txt └── target-not-found │ ├── .env.dist │ └── error.txt └── valid ├── changed-values ├── .env ├── .env.dist └── expected.log ├── extra-values ├── .env ├── .env.dist └── expected.log ├── identical ├── .env ├── .env.dist └── expected.log ├── missed-values ├── .env ├── .env.dist └── expected.log └── mixed ├── .env ├── .env.dist └── expected.log /.codeclimate.yml: -------------------------------------------------------------------------------- 1 | engines: 2 | duplication: 3 | enabled: true 4 | config: 5 | languages: 6 | - php 7 | fixme: 8 | enabled: true 9 | phpcodesniffer: 10 | enabled: true 11 | phan: 12 | enabled: true 13 | config: 14 | file_extensions: "php" 15 | ignore-undeclared: true 16 | dead-code-detection: true 17 | backward-compatibility-checks: true 18 | checks: 19 | PhanParamTooMany: 20 | enabled: false 21 | phpmd: 22 | enabled: true 23 | checks: 24 | CleanCode/StaticAccess: 25 | enabled: false 26 | Naming/ShortVariable: 27 | enabled: false 28 | ratings: 29 | paths: 30 | - "**.php" 31 | 32 | exclude_paths: 33 | - tests/ 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | composer.lock 2 | phpunit.xml 3 | vendor 4 | -------------------------------------------------------------------------------- /.scrutinizer.yml: -------------------------------------------------------------------------------- 1 | filter: 2 | excluded_paths: [tests/*, vendor] 3 | 4 | checks: 5 | php: 6 | code_rating: true 7 | remove_extra_empty_lines: true 8 | remove_php_closing_tag: true 9 | remove_trailing_whitespace: true 10 | fix_use_statements: 11 | remove_unused: true 12 | preserve_multiple: false 13 | preserve_blanklines: true 14 | order_alphabetically: true 15 | fix_php_opening_tag: true 16 | fix_linefeed: true 17 | fix_line_ending: true 18 | fix_identation_4spaces: true 19 | fix_doc_comments: true 20 | 21 | tools: 22 | php_analyzer: true 23 | php_code_sniffer: 24 | config: 25 | standard: PSR2 26 | filter: 27 | paths: ['src'] 28 | php_loc: 29 | enabled: true 30 | excluded_dirs: [vendor, tests] 31 | php_cpd: 32 | enabled: true 33 | excluded_dirs: [vendor, tests] 34 | 35 | build: 36 | tests: 37 | override: 38 | - 39 | command: 'vendor/bin/phpunit --coverage-clover=some-file' 40 | coverage: 41 | file: 'some-file' 42 | format: 'clover' 43 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | dist: trusty 4 | 5 | cache: 6 | directories: 7 | - $HOME/.composer/cache/files 8 | 9 | php: 10 | - 5.6 11 | - 7.0 12 | - 7.1 13 | - hhvm 14 | 15 | before_script: 16 | - composer install 17 | 18 | script: 19 | - vendor/bin/phpunit --coverage-clover=phpunit.coverage.xml --log-junit=phpunit.report.xml 20 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 1.0.0 (2017-05-14) 2 | 3 | * Initial release of the library. 4 | 5 | # 1.0.1 (2017-06-01) 6 | 7 | * Update README.md 8 | * Fix travis.yml 9 | * Fix bug in ComposerIO 10 | * Update output messages 11 | 12 | # 1.0.2 (2017-06-05) 13 | 14 | * Remove comments from destination file 15 | * Improve console output messages 16 | * Set "actualize" command as default. 17 | 18 | # 1.0.3 (2017-08-31) 19 | 20 | * Fix config key mismatch 21 | * Update Readme.md 22 | 23 | # 1.1.0 (2018-04-20) 24 | 25 | * Add Symfony 4 support (@craigruks) 26 | -------------------------------------------------------------------------------- /CNAME: -------------------------------------------------------------------------------- 1 | design.magnit.ru -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017 Lexey Felde 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is furnished 8 | to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # EnvDiff 2 | 3 | [![Latest Version on Packagist][ico-version]][link-packagist] 4 | [![Software License][ico-license]](LICENSE.md) 5 | [![Build Status][ico-travis]][link-travis] 6 | [![Coverage Status][ico-scrutinizer]][link-scrutinizer] 7 | [![Quality Score][ico-code-quality]][link-code-quality] 8 | 9 | EnvDiff is tool to compare environment keys to find the difference between .env files and actualize them. 10 | 11 | ![Example cast](https://j.gifs.com/y8RGA6.gif) 12 | 13 | # Installation 14 | 15 | ``` 16 | composer require tekill/env-diff 17 | ``` 18 | 19 | ## Manual running 20 | ### Actualize variables 21 | Compare `.env` with `.env.dist` and add missing variables to `.env` file. 22 | ``` 23 | php ./vendor/bin/env-diff actualize 24 | ``` 25 | 26 | Compare `.env` with `.env.example` and add missing variables to `.env` file. 27 | ``` 28 | php ./vendor/bin/env-diff actualize .env.example 29 | ``` 30 | 31 | Compare `.env-target` with `.env.example` and add missing variables to `.env-target` file. 32 | ``` 33 | php ./vendor/bin/env-diff actualize .env.example .env-target 34 | ``` 35 | 36 | If you want to delete outdated values just run command with `-k=false` option. 37 | 38 | ``` 39 | php ./vendor/bin/env-diff actualize -k=false 40 | ``` 41 | 42 | ### Show differences 43 | Command has same interface, arguments and options. 44 | 45 | Compare `.env` with `.env.dist` and show differences between them. 46 | ``` 47 | php ./vendor/bin/env-diff diff 48 | ``` 49 | 50 | ## Composer script 51 | 52 | Add code block in `composer.json`: 53 | ```$json 54 | "scripts": { 55 | "post-update-cmd": "LF\\EnvDiff\\Composer\\ScriptHandler::actualizeEnv" 56 | } 57 | ``` 58 | 59 | The `.env` will then be created or updated by the composer script, to match the structure of the dist 60 | file `.env.dist` by asking you the missing variables. 61 | 62 | By default, the dist file is assumed to be in the same place than the target `.env` 63 | file, suffixed by `.dist`. This can be changed in the configuration: 64 | 65 | ```json 66 | { 67 | "extra": { 68 | "lf-env-diff": [ 69 | { 70 | "dist": "path/to/env.dist", 71 | "target": "path/to/.env" 72 | } 73 | ] 74 | } 75 | } 76 | ``` 77 | 78 | The script handler will ask you interactively for variables which are missing 79 | in the target env file, using the value of the dist file as default value. 80 | If composer is run in a non-interactive mode `--no-interaction`, the values of the dist file 81 | will be used for missing variables. 82 | 83 | **Warning:** This handler will overwrite any comments or spaces into your target `.env` file so handle with care. 84 | 85 | ### Managing multiple ignored files 86 | 87 | The handler can manage multiple ignored files. To use this feature, the `lf-env-diff` extra should contain a 88 | JSON array with multiple configurations inside it instead of a configuration object: 89 | 90 | ```json 91 | { 92 | "extra": { 93 | "lf-env-diff": [ 94 | { 95 | "dist": "path/to/.env.dist", 96 | "target": "path/to/.env" 97 | }, 98 | { 99 | "dist": "path/to/.env.dist", 100 | "target": "path/to/.env-test", 101 | "keep-outdated": false 102 | } 103 | ] 104 | } 105 | } 106 | ``` 107 | 108 | ### Show difference 109 | 110 | Add code block in `composer.json`: 111 | ```$json 112 | "scripts": { 113 | "post-update-cmd": "LF\\EnvDiff\\Composer\\ScriptHandler::showDifference" 114 | } 115 | ``` 116 | 117 | This handler has same behavior as described before. 118 | 119 | ## Git hooks 120 | 121 | You can use Git hook that gets triggered after any 'git pull' whenever one of the files specified has changed. 122 | Useful to update any web application dependency or sync configuration. 123 | 124 | Create `post-merge` hook in `.git/hooks` directory of your project: 125 | ``` 126 | #/usr/bin/env bash 127 | 128 | changed_files="$(git diff-tree -r --name-only --no-commit-id ORIG_HEAD HEAD)" 129 | 130 | check_run() { 131 | echo "$changed_files" | grep -E --quiet "$1" && eval "$2" 132 | } 133 | 134 | # Actualize env files if the `env.dist` file gets changed 135 | check_run env.dist "php ./vendor/bin/env-diff actualize" 136 | ``` 137 | 138 | [ico-version]: https://img.shields.io/packagist/v/Tekill/env-diff.svg?style=flat-square 139 | [ico-license]: https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square 140 | [ico-travis]: https://img.shields.io/travis/Tekill/env-diff/master.svg?style=flat-square 141 | [ico-scrutinizer]: https://img.shields.io/scrutinizer/coverage/g/Tekill/env-diff.svg?style=flat-square 142 | [ico-code-quality]: https://img.shields.io/scrutinizer/g/Tekill/env-diff.svg?style=flat-square 143 | 144 | [link-packagist]: https://packagist.org/packages/Tekill/env-diff 145 | [link-travis]: https://travis-ci.org/Tekill/env-diff 146 | [link-scrutinizer]: https://scrutinizer-ci.com/g/Tekill/env-diff/code-structure/ 147 | [link-code-quality]: https://scrutinizer-ci.com/g/Tekill/env-diff 148 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tekill/env-diff", 3 | "description": "Check the difference between env files and actualize each other", 4 | "type": "library", 5 | "license": "MIT", 6 | "authors": [ 7 | { 8 | "name": "Lexey Felde", 9 | "email": "felde.lexey@gmail.com" 10 | } 11 | ], 12 | "require": { 13 | "php": ">=5.6", 14 | "symfony/console": "~2.8|~3.0|~4.0" 15 | }, 16 | "require-dev": { 17 | "composer/composer": "1.0.*@dev", 18 | "phpunit/phpunit": "^5.0" 19 | }, 20 | "autoload": { 21 | "psr-4": { "LF\\EnvDiff\\": "src/" } 22 | }, 23 | "bin": [ 24 | "env-diff" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /env-diff: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | run(); 19 | } 20 | } 21 | 22 | fwrite( 23 | STDERR, 24 | 'You need to set up the project dependencies using Composer:' . PHP_EOL . PHP_EOL . 25 | ' composer install' . PHP_EOL . PHP_EOL . 26 | 'You can learn all about Composer on https://getcomposer.org/.' . PHP_EOL 27 | ); 28 | 29 | exit(1); 30 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ./tests/ 7 | 8 | 9 | 10 | 11 | 12 | ./src 13 | 14 | ./tests 15 | ./vendor 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/Composer/ScriptHandler.php: -------------------------------------------------------------------------------- 1 | getIO())); 26 | 27 | foreach ($configs as $config) { 28 | $processor->actualizeEnv(Config::createFormArray($config)); 29 | } 30 | } 31 | 32 | /** 33 | * @param Event $event 34 | * 35 | * @throws InvalidArgumentException 36 | * @throws RuntimeException 37 | */ 38 | public static function showDifference(Event $event) 39 | { 40 | $configs = self::extractConfigs($event); 41 | $processor = new Processor(new ComposerIO($event->getIO())); 42 | 43 | foreach ($configs as $config) { 44 | $processor->showDifference(Config::createFormArray($config)); 45 | } 46 | } 47 | 48 | /** 49 | * @param Event $event 50 | * 51 | * @return array 52 | * 53 | * @throws InvalidArgumentException 54 | */ 55 | private static function extractConfigs(Event $event) 56 | { 57 | $extras = $event->getComposer()->getPackage()->getExtra(); 58 | 59 | $configs = isset($extras[self::CONFIG_KEY]) ? $extras[self::CONFIG_KEY] : [[]]; 60 | 61 | if (!is_array($configs)) { 62 | throw new InvalidArgumentException( 63 | 'The extra.lf-env-diff setting must be an array or a configuration object' 64 | ); 65 | } 66 | 67 | foreach ($configs as $config) { 68 | if (!is_array($config)) { 69 | throw new InvalidArgumentException( 70 | 'The extra.lf-env-diff setting must be an array of configuration objects' 71 | ); 72 | } 73 | } 74 | 75 | return $configs; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/Config.php: -------------------------------------------------------------------------------- 1 | dist = $dist; 29 | $this->target = $target; 30 | $this->keepOutdatedEnv = $keepOutdatedEnv; 31 | } 32 | 33 | /** 34 | * @param array $config 35 | * 36 | * @return static 37 | */ 38 | public static function createFormArray(array $config = []) 39 | { 40 | if (empty($config['target'])) { 41 | $config['target'] = '.env'; 42 | } 43 | if (empty($config['dist'])) { 44 | $config['dist'] = $config['target'] . '.dist'; 45 | } 46 | if (!isset($config['keep-outdated'])) { 47 | $config['keep-outdated'] = true; 48 | } 49 | 50 | return new static($config['dist'], $config['target'], (bool) $config['keep-outdated']); 51 | } 52 | 53 | /** 54 | * @return string 55 | */ 56 | public function getDist() 57 | { 58 | return $this->dist; 59 | } 60 | 61 | /** 62 | * @return string 63 | */ 64 | public function getTarget() 65 | { 66 | return $this->target; 67 | } 68 | 69 | /** 70 | * @return boolean 71 | */ 72 | public function isKeepOutdatedEnv() 73 | { 74 | return $this->keepOutdatedEnv; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/Console/Application.php: -------------------------------------------------------------------------------- 1 | setAutoExit(true); 22 | $this->add(new DiffCommand('diff')); 23 | $this->add(new ActualizeCommand('actualize')); 24 | 25 | $this->setDefaultCommand('actualize'); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Console/Command/AbstractCommand.php: -------------------------------------------------------------------------------- 1 | addArgument('dist', InputOption::VALUE_REQUIRED, 'From file', Config::DEFAULT_DIST) 23 | ->addArgument('target', InputOption::VALUE_REQUIRED, 'To file', Config::DEFAULT_TARGET) 24 | ->addOption('keep-outdated', 'k', InputOption::VALUE_OPTIONAL, 'Keep old env variables', true); 25 | } 26 | 27 | /** 28 | * {@inheritdoc} 29 | * 30 | * @throws InvalidArgumentException 31 | */ 32 | protected function execute(InputInterface $input, OutputInterface $output) 33 | { 34 | $config = $this->createConfig($input); 35 | $processor = $this->createProcessor($input, $output); 36 | 37 | $this->doExecute($processor, $config); 38 | 39 | return 0; 40 | } 41 | 42 | /** 43 | * @param InputInterface $input 44 | * 45 | * @return Config 46 | * 47 | * @throws InvalidArgumentException 48 | */ 49 | private function createConfig(InputInterface $input) 50 | { 51 | $dist = $input->getArgument('dist'); 52 | $target = $input->getArgument('target'); 53 | $keepOutdated = $input->getOption('keep-outdated'); 54 | 55 | return new Config($dist, $target, $keepOutdated); 56 | } 57 | 58 | /** 59 | * @param InputInterface $input 60 | * @param OutputInterface $output 61 | * 62 | * @return Processor 63 | */ 64 | private function createProcessor(InputInterface $input, OutputInterface $output) 65 | { 66 | return new Processor(new ConsoleIO($input, $output)); 67 | } 68 | 69 | /** 70 | * @param Processor $processor 71 | * @param Config $config 72 | */ 73 | abstract protected function doExecute(Processor $processor, Config $config); 74 | } 75 | -------------------------------------------------------------------------------- /src/Console/Command/ActualizeCommand.php: -------------------------------------------------------------------------------- 1 | actualizeEnv($config); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Console/Command/DiffCommand.php: -------------------------------------------------------------------------------- 1 | showDifference($config); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Env.php: -------------------------------------------------------------------------------- 1 | dump($envArray); 19 | } 20 | 21 | /** 22 | * @param string $path 23 | * 24 | * @return array 25 | * 26 | * @throws InvalidArgumentException 27 | */ 28 | public static function parse($path) 29 | { 30 | return (new Parser())->parse($path); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Env/Dumper.php: -------------------------------------------------------------------------------- 1 | $variable) { 17 | $dump .= sprintf('%s=%s%s', $env, $variable, PHP_EOL); 18 | } 19 | 20 | return trim($dump); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Env/Parser.php: -------------------------------------------------------------------------------- 1 | isCommentOrEmpty($line)) { 31 | continue; 32 | } 33 | if (false === strpos($line, '=')) { 34 | throw new InvalidArgumentException( 35 | sprintf('Parse error at %d line: `%s` is not valid env value', $number, $line) 36 | ); 37 | } 38 | 39 | list($name, $value) = explode('=', $line, 2); 40 | $env[trim($name)] = trim($value); 41 | } 42 | 43 | fclose($file); 44 | 45 | return $env; 46 | } 47 | 48 | /** 49 | * @param string $line 50 | * 51 | * @return bool 52 | */ 53 | private function isCommentOrEmpty($line) 54 | { 55 | return (mb_strlen($line) === 0 || $line[0] === '#'); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/IO/ComposerIO.php: -------------------------------------------------------------------------------- 1 | io = $io; 23 | } 24 | 25 | /** 26 | * @param string $message 27 | */ 28 | public function write($message) 29 | { 30 | $this->io->write($message); 31 | } 32 | 33 | /** 34 | * @return bool 35 | */ 36 | public function isInteractive() 37 | { 38 | return $this->io->isInteractive(); 39 | } 40 | 41 | /** 42 | * @param string $question 43 | * @param string|null $default 44 | * 45 | * @return string 46 | * 47 | * @throws \RuntimeException 48 | */ 49 | public function ask($question, $default = null) 50 | { 51 | return $this->io->ask($question, $default); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/IO/ConsoleIO.php: -------------------------------------------------------------------------------- 1 | input = $input; 33 | $this->output = $output; 34 | $this->questionHelper = new QuestionHelper(); 35 | } 36 | 37 | /** 38 | * @param string $message 39 | */ 40 | public function write($message) 41 | { 42 | $this->output->writeln($message); 43 | } 44 | 45 | /** 46 | * @return bool 47 | */ 48 | public function isInteractive() 49 | { 50 | return $this->input->isInteractive(); 51 | } 52 | 53 | /** 54 | * @param string $question 55 | * @param string|null $default 56 | * 57 | * @return string 58 | * 59 | * @throws \RuntimeException 60 | */ 61 | public function ask($question, $default = null) 62 | { 63 | return $this->questionHelper->ask($this->input, $this->output, new Question($question, $default)); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/IO/IOInterface.php: -------------------------------------------------------------------------------- 1 | io = $io; 22 | } 23 | 24 | /** 25 | * @param Config $config 26 | * 27 | * @throws InvalidArgumentException 28 | * @throws RuntimeException 29 | * 30 | * @return bool 31 | */ 32 | public function actualizeEnv(Config $config) 33 | { 34 | $dist = $config->getDist(); 35 | $target = $config->getTarget(); 36 | $exists = is_file($target); 37 | 38 | $this->io->write(sprintf('Actualize env from "%s"', $dist)); 39 | 40 | try { 41 | $distEnv = Env::parse($dist); 42 | $actualEnv = $exists ? Env::parse($target) : []; 43 | } catch (InvalidArgumentException $exception) { 44 | $this->io->write(sprintf('%s, abort', $exception->getMessage())); 45 | 46 | return true; 47 | } 48 | 49 | $actualEnv = $this->processEnv($distEnv, $actualEnv, $config->isKeepOutdatedEnv()); 50 | 51 | if (!is_dir($dir = dirname($target))) { 52 | mkdir($dir, 0755, true); 53 | } 54 | 55 | ksort($actualEnv); 56 | file_put_contents($target, Env::dump($actualEnv)); 57 | 58 | $this->io->write(sprintf('"%s" has been %s', $target, $exists ? 'updated' : 'created')); 59 | 60 | return false; 61 | } 62 | 63 | /** 64 | * @param Config $config 65 | * 66 | * @throws InvalidArgumentException 67 | * 68 | * @return bool 69 | */ 70 | public function showDifference(Config $config) 71 | { 72 | $dist = $config->getDist(); 73 | $target = $config->getTarget(); 74 | 75 | try { 76 | $distEnv = Env::parse($dist); 77 | $actualEnv = Env::parse($target); 78 | } catch (InvalidArgumentException $exception) { 79 | $this->io->write(sprintf('%s', $exception->getMessage())); 80 | 81 | return true; 82 | } 83 | 84 | $extraEnv = array_diff_key($actualEnv, $distEnv); 85 | $missingEnv = array_diff_key($distEnv, $actualEnv); 86 | $changedEnv = array_diff(array_intersect_key($distEnv, $actualEnv), $actualEnv); 87 | 88 | if (!count($missingEnv) && !count($extraEnv) && !count($changedEnv)) { 89 | $this->io->write(sprintf('"%s" and "%s" is identical', $target, $dist)); 90 | 91 | return false; 92 | } 93 | 94 | $this->io->write(sprintf('Diff between "%s" and "%s" files:', $target, $dist)); 95 | $this->io->write(''); 96 | 97 | foreach ($missingEnv as $env => $value) { 98 | $this->io->write(sprintf('- %s=%s', $env, $value)); 99 | } 100 | foreach ($extraEnv as $env => $value) { 101 | $this->io->write(sprintf('+ %s=%s', $env, $value)); 102 | } 103 | foreach ($changedEnv as $env => $default) { 104 | $this->io->write(sprintf('@ %s=%s (%s)', $env, $actualEnv[$env], $default)); 105 | } 106 | 107 | return false; 108 | } 109 | 110 | /** 111 | * @param array $expectedEnv 112 | * @param array $actualEnv 113 | * @param bool $keepOutdated 114 | * 115 | * @return array 116 | * 117 | * @throws RuntimeException 118 | */ 119 | private function processEnv(array $expectedEnv, array $actualEnv, $keepOutdated) 120 | { 121 | if (false === $keepOutdated) { 122 | $actualEnv = array_intersect_key($actualEnv, $expectedEnv); 123 | } 124 | 125 | return $this->getEnv($expectedEnv, $actualEnv); 126 | } 127 | 128 | /** 129 | * @param array $expectedEnv 130 | * @param array $actualEnv 131 | * 132 | * @return array 133 | * 134 | * @throws RuntimeException 135 | */ 136 | private function getEnv(array $expectedEnv, array $actualEnv) 137 | { 138 | if (!$this->io->isInteractive()) { 139 | return array_replace($expectedEnv, $actualEnv); 140 | } 141 | 142 | $diffEnv = array_diff_key($expectedEnv, $actualEnv); 143 | if (count($diffEnv) > 0) { 144 | $this->io->write('Some env variables are missing. Please provide them.'); 145 | 146 | foreach ($diffEnv as $env => $default) { 147 | $actualEnv[$env] = $this->io->ask( 148 | sprintf('%s (%s): ', $env, $default), 149 | $default 150 | ); 151 | } 152 | } 153 | 154 | return $actualEnv; 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /tests/Composer/ScriptHandlerTest.php: -------------------------------------------------------------------------------- 1 | [ 23 | ['lf-env-diff' => 'not an array'], 24 | 'The extra.lf-env-diff setting must be an array or a configuration object', 25 | ], 26 | 'invalid type for multiple configs' => [ 27 | ['lf-env-diff' => ['not an array']], 28 | 'The extra.lf-env-diff setting must be an array of configuration objects', 29 | ], 30 | ]; 31 | } 32 | 33 | /** 34 | * @dataProvider provideInvalidConfiguration() 35 | * 36 | * @param array $extras 37 | * @param string $exceptionMessage 38 | */ 39 | public function testActualizeEnvInvalidConfiguration(array $extras, $exceptionMessage) 40 | { 41 | $this->expectException(InvalidArgumentException::class); 42 | $this->expectExceptionMessage($exceptionMessage); 43 | 44 | $event = $this->createEvent($extras); 45 | $event 46 | ->expects(self::never()) 47 | ->method('getIO'); 48 | 49 | ScriptHandler::actualizeEnv($event); 50 | } 51 | 52 | /** 53 | * @dataProvider provideInvalidConfiguration() 54 | * 55 | * @param array $extras 56 | * @param string $exceptionMessage 57 | */ 58 | public function testShowDifferenceInvalidConfiguration(array $extras, $exceptionMessage) 59 | { 60 | $this->expectException(InvalidArgumentException::class); 61 | $this->expectExceptionMessage($exceptionMessage); 62 | 63 | $event = $this->createEvent($extras); 64 | $event 65 | ->expects(self::never()) 66 | ->method('getIO'); 67 | 68 | ScriptHandler::showDifference($event); 69 | } 70 | 71 | /** 72 | * @return array 73 | */ 74 | public function provideValidConfiguration() 75 | { 76 | return [ 77 | [ 78 | [ 79 | 'lf-env-diff' => [ 80 | [ 81 | 'dist' => 'fixtures/difference/valid/identical/.env.dist', 82 | 'target' => 'fixtures/difference/valid/identical/.env' 83 | ], 84 | [ 85 | 'dist' => 'fixtures/difference/valid/identical/.env.dist', 86 | 'target' => 'fixtures/difference/valid/identical/.env' 87 | ] 88 | ] 89 | ] 90 | ] 91 | ]; 92 | } 93 | 94 | /** 95 | * @dataProvider provideValidConfiguration() 96 | * 97 | * @param array $extras 98 | */ 99 | public function testActualizeEnvValidConfiguration(array $extras) 100 | { 101 | $io = $this->createMock(IOInterface::class); 102 | 103 | $event = $this->createEvent($extras); 104 | $event 105 | ->expects(self::once()) 106 | ->method('getIO') 107 | ->willReturn($io); 108 | 109 | chdir(dirname(__DIR__)); 110 | ScriptHandler::actualizeEnv($event); 111 | } 112 | 113 | /** 114 | * @dataProvider provideValidConfiguration() 115 | * 116 | * @param array $extras 117 | */ 118 | public function testShowDifferenceValidConfiguration(array $extras) 119 | { 120 | $io = $this->createMock(IOInterface::class); 121 | 122 | $event = $this->createEvent($extras); 123 | $event 124 | ->expects(self::once()) 125 | ->method('getIO') 126 | ->willReturn($io); 127 | 128 | chdir(dirname(__DIR__)); 129 | ScriptHandler::showDifference($event); 130 | } 131 | 132 | /** 133 | * @param array $extras 134 | * 135 | * @return PHPUnit_Framework_MockObject_MockObject | Event 136 | */ 137 | private function createEvent(array $extras = []) 138 | { 139 | $package = $this->createMock(PackageInterface::class); 140 | $package->expects(self::once()) 141 | ->method('getExtra') 142 | ->willReturn($extras); 143 | 144 | $composer = $this->createMock(Composer::class); 145 | $composer->expects(self::once()) 146 | ->method('getPackage') 147 | ->willReturn($package); 148 | 149 | $event = $this->createMock(Event::class); 150 | $event->expects(self::once()) 151 | ->method('getComposer') 152 | ->willReturn($composer); 153 | 154 | return $event; 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /tests/ConfigTest.php: -------------------------------------------------------------------------------- 1 | [ 17 | [], 18 | new Config('.env.dist', '.env') 19 | ], 20 | 'custom target' => [ 21 | ['target' => '.custom'], 22 | new Config('.custom.dist', '.custom') 23 | ], 24 | 'custom target & dist' => [ 25 | ['target' => '.custom', 'dist' => '.env.dist'], 26 | new Config('.env.dist', '.custom') 27 | ], 28 | 'keep-outdated is false' => [ 29 | ['keep-outdated' => false], 30 | new Config('.env.dist', '.env', false) 31 | ] 32 | ]; 33 | } 34 | 35 | /** 36 | * @dataProvider createFromArrayDataProvider() 37 | * 38 | * @param array $array 39 | * @param Config $expected 40 | */ 41 | public function testCreateFromArray(array $array, Config $expected) 42 | { 43 | self::assertEquals($expected, Config::createFormArray($array)); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /tests/Console/ApplicationTest.php: -------------------------------------------------------------------------------- 1 | has('diff')); 15 | self::assertTrue($application->has('actualize')); 16 | self::assertTrue($application->isAutoExitEnabled()); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tests/Console/Command/CommandsTest.php: -------------------------------------------------------------------------------- 1 | [new DiffCommand('name')], 21 | 'actualize' => [new ActualizeCommand('name')], 22 | ]; 23 | } 24 | 25 | /** 26 | * @dataProvider dataRun() 27 | * 28 | * @param Command $command 29 | */ 30 | public function testRun(Command $command) 31 | { 32 | $input = $this 33 | ->getMockBuilder(Input::class) 34 | ->disableOriginalConstructor() 35 | ->getMock(); 36 | $output = $this 37 | ->getMockBuilder(Output::class) 38 | ->disableOriginalConstructor() 39 | ->setMethods(['write', 'doWrite']) 40 | ->getMock(); 41 | $output->expects(self::atLeastOnce()) 42 | ->method('write'); 43 | 44 | self::assertEquals( 45 | 0, 46 | $command->run($input, $output) 47 | ); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /tests/ProcessorTest.php: -------------------------------------------------------------------------------- 1 | io = $this->createMock(IOInterface::class); 24 | $this->processor = new Processor($this->io); 25 | } 26 | 27 | /** 28 | * @return array 29 | */ 30 | public function actualizeEnvDataProvider() 31 | { 32 | $config = Config::createFormArray( 33 | [ 34 | 'dist' => '.env.dist', 35 | 'target' => '.env' 36 | ] 37 | ); 38 | $tests = []; 39 | 40 | foreach (glob(__DIR__ . '/fixtures/actualize/valid/*/') as $folder) { 41 | $tests[basename($folder)] = [$folder, $config, false]; 42 | $tests[basename($folder) . ' interactive'] = [$folder, $config, true]; 43 | } 44 | 45 | $subdirectory = realpath(__DIR__ . '/fixtures/actualize/subdirectory/') . '/'; 46 | $configSubdirectory = Config::createFormArray( 47 | [ 48 | 'dist' => 'sub/.env.dist', 49 | 'target' => 'expected/.env' 50 | ] 51 | ); 52 | 53 | $tests[$subdirectory] = [$subdirectory, $configSubdirectory, false]; 54 | $tests[$subdirectory . ' interactive'] = [$subdirectory, $configSubdirectory, false]; 55 | 56 | return $tests; 57 | } 58 | 59 | /** 60 | * @dataProvider actualizeEnvDataProvider() 61 | * 62 | * @param string $directory 63 | * @param Config $config 64 | * @param bool $isInteractive 65 | */ 66 | public function testActualizeEnv($directory, Config $config, $isInteractive) 67 | { 68 | $workingDir = sys_get_temp_dir() . '/lf_env_diff_tests/'; 69 | $fs = new Filesystem(); 70 | 71 | if (is_dir($workingDir)) { 72 | $fs->remove($workingDir); 73 | } 74 | 75 | $fs->copy($directory . $config->getDist(), $workingDir . $config->getDist()); 76 | 77 | if ($exists = file_exists($directory . '/' . $config->getTarget())) { 78 | $fs->copy($directory . $config->getTarget(), $workingDir . $config->getTarget()); 79 | } 80 | 81 | chdir($workingDir); 82 | $this->io->expects(self::once()) 83 | ->method('isInteractive') 84 | ->willReturn($isInteractive); 85 | $this->io->expects(self::any()) 86 | ->method('write'); 87 | $this->io->expects(self::any()) 88 | ->method('ask') 89 | ->willReturnArgument(1); 90 | 91 | self::assertFalse( 92 | $this->processor->actualizeEnv($config) 93 | ); 94 | self::assertFileEquals( 95 | $directory . '/.expected', 96 | $workingDir . $config->getTarget() 97 | ); 98 | } 99 | 100 | /** 101 | * @return array 102 | */ 103 | public function actualizeEnvDataWithRemoveOutdatedProvider() 104 | { 105 | $tests = []; 106 | 107 | $subdirectory = realpath(__DIR__ . '/fixtures/actualize/delete-old-variable/') . '/'; 108 | $configSubdirectory = new Config('.env.dist', '.env', false); 109 | 110 | $tests[$subdirectory] = [$subdirectory, $configSubdirectory, false]; 111 | $tests[$subdirectory . ' interactive'] = [$subdirectory, $configSubdirectory, false]; 112 | 113 | return $tests; 114 | } 115 | 116 | /** 117 | * @dataProvider actualizeEnvDataWithRemoveOutdatedProvider() 118 | * 119 | * @param string $directory 120 | * @param Config $config 121 | * @param bool $isInteractive 122 | */ 123 | public function testActualizeEnvWithRemoveOutdated($directory, Config $config, $isInteractive) 124 | { 125 | $workingDir = sys_get_temp_dir() . '/lf_env_diff_tests/'; 126 | $fs = new Filesystem(); 127 | 128 | if (is_dir($workingDir)) { 129 | $fs->remove($workingDir); 130 | } 131 | 132 | $fs->copy($directory . $config->getDist(), $workingDir . $config->getDist()); 133 | 134 | if ($exists = file_exists($directory . '/' . $config->getTarget())) { 135 | $fs->copy($directory . $config->getTarget(), $workingDir . $config->getTarget()); 136 | } 137 | 138 | chdir($workingDir); 139 | $this->io->expects(self::once()) 140 | ->method('isInteractive') 141 | ->willReturn($isInteractive); 142 | $this->io->expects(self::any()) 143 | ->method('write'); 144 | $this->io->expects(self::any()) 145 | ->method('ask') 146 | ->willReturnArgument(1); 147 | 148 | self::assertFalse( 149 | $this->processor->actualizeEnv($config) 150 | ); 151 | self::assertFileEquals( 152 | $directory . '/.expected', 153 | $workingDir . $config->getTarget() 154 | ); 155 | } 156 | 157 | /** 158 | * @return array 159 | */ 160 | public function actualizeEnvParseFailedDataProvider() 161 | { 162 | $invalidDirectory = 'fixtures/actualize/invalid/'; 163 | $tests = []; 164 | 165 | foreach (scandir(__DIR__ . '/' . $invalidDirectory) as $folder) { 166 | if ($folder === '.' || $folder === '..') { 167 | continue; 168 | } 169 | $tests[basename($folder)] = [ 170 | new Config($invalidDirectory . $folder . '/.env.dist'), 171 | file_get_contents(__DIR__ . '/' . $invalidDirectory . $folder . '/error.txt') 172 | ]; 173 | } 174 | 175 | return $tests; 176 | } 177 | 178 | /** 179 | * @dataProvider actualizeEnvParseFailedDataProvider() 180 | * 181 | * @param Config $config 182 | * @param string $errorMessage 183 | */ 184 | public function testActualizeEnvParseFailed(Config $config, $errorMessage) 185 | { 186 | $this->io->expects(self::at(1)) 187 | ->method('write') 188 | ->with($errorMessage); 189 | 190 | chdir(__DIR__); 191 | self::assertTrue( 192 | $this->processor->actualizeEnv($config) 193 | ); 194 | } 195 | 196 | /** 197 | * @return array 198 | */ 199 | public function showDifferenceDataProvider() 200 | { 201 | $tests = []; 202 | 203 | foreach (glob(__DIR__ . '/fixtures/difference/valid/*/') as $folder) { 204 | $tests[basename($folder)] = [$folder, file($folder . 'expected.log')]; 205 | } 206 | 207 | return $tests; 208 | } 209 | 210 | /** 211 | * @dataProvider showDifferenceDataProvider() 212 | * 213 | * @param string $directory 214 | * @param array $lines 215 | */ 216 | public function testShowDifference($directory, array $lines) 217 | { 218 | $config = Config::createFormArray( 219 | [ 220 | 'dist' => '.env.dist', 221 | 'target' => '.env' 222 | ] 223 | ); 224 | 225 | foreach ($lines as $id => $line) { 226 | $this->io->expects(self::at($id)) 227 | ->method('write') 228 | ->with(trim($line)); 229 | } 230 | 231 | chdir($directory); 232 | 233 | self::assertFalse( 234 | $this->processor->showDifference($config) 235 | ); 236 | } 237 | 238 | /** 239 | * @return array 240 | */ 241 | public function showDifferenceParseFailedDataProvider() 242 | { 243 | $invalidDirectory = 'fixtures/difference/invalid/'; 244 | $tests = []; 245 | 246 | foreach (scandir(__DIR__ . '/' . $invalidDirectory) as $folder) { 247 | if ($folder === '.' || $folder === '..') { 248 | continue; 249 | } 250 | $tests[basename($folder)] = [ 251 | new Config($invalidDirectory . $folder . '/.env.dist', $invalidDirectory . $folder . '/.env'), 252 | file_get_contents(__DIR__ . '/' . $invalidDirectory . $folder . '/error.txt') 253 | ]; 254 | } 255 | 256 | return $tests; 257 | } 258 | 259 | /** 260 | * @dataProvider showDifferenceParseFailedDataProvider() 261 | * 262 | * @param Config $config 263 | * @param string $errorMessage 264 | */ 265 | public function testShowDifferenceFailed(Config $config, $errorMessage) 266 | { 267 | $this->io->expects(self::once()) 268 | ->method('write') 269 | ->with($errorMessage); 270 | 271 | chdir(__DIR__); 272 | self::assertTrue( 273 | $this->processor->showDifference($config) 274 | ); 275 | } 276 | } 277 | -------------------------------------------------------------------------------- /tests/fixtures/actualize/delete-old-variable/.env: -------------------------------------------------------------------------------- 1 | FOO='bar' 2 | SOME_VARIABLE='old' 3 | -------------------------------------------------------------------------------- /tests/fixtures/actualize/delete-old-variable/.env.dist: -------------------------------------------------------------------------------- 1 | FOO='bar' -------------------------------------------------------------------------------- /tests/fixtures/actualize/delete-old-variable/.expected: -------------------------------------------------------------------------------- 1 | FOO='bar' -------------------------------------------------------------------------------- /tests/fixtures/actualize/invalid/dist-not-found/error.txt: -------------------------------------------------------------------------------- 1 | The file "fixtures/actualize/invalid/dist-not-found/.env.dist" does not exist, abort -------------------------------------------------------------------------------- /tests/fixtures/actualize/invalid/invalid-delimiter/.env.dist: -------------------------------------------------------------------------------- 1 | FOO:'bar' -------------------------------------------------------------------------------- /tests/fixtures/actualize/invalid/invalid-delimiter/error.txt: -------------------------------------------------------------------------------- 1 | Parse error at 1 line: `FOO:'bar'` is not valid env value, abort -------------------------------------------------------------------------------- /tests/fixtures/actualize/invalid/invalid-string/.env.dist: -------------------------------------------------------------------------------- 1 | this is not a valid env variable -------------------------------------------------------------------------------- /tests/fixtures/actualize/invalid/invalid-string/error.txt: -------------------------------------------------------------------------------- 1 | Parse error at 1 line: `this is not a valid env variable` is not valid env value, abort -------------------------------------------------------------------------------- /tests/fixtures/actualize/subdirectory/.expected: -------------------------------------------------------------------------------- 1 | APPEND='new line' 2 | FOO='bar' -------------------------------------------------------------------------------- /tests/fixtures/actualize/subdirectory/sub/.env.dist: -------------------------------------------------------------------------------- 1 | FOO= 'bar' 2 | 3 | APPEND = 'new line' -------------------------------------------------------------------------------- /tests/fixtures/actualize/valid/append-new-variable/.env: -------------------------------------------------------------------------------- 1 | FOO='bar' -------------------------------------------------------------------------------- /tests/fixtures/actualize/valid/append-new-variable/.env.dist: -------------------------------------------------------------------------------- 1 | # Line with comment 2 | FOO='bar' 3 | APPEND='new line' -------------------------------------------------------------------------------- /tests/fixtures/actualize/valid/append-new-variable/.expected: -------------------------------------------------------------------------------- 1 | APPEND='new line' 2 | FOO='bar' -------------------------------------------------------------------------------- /tests/fixtures/actualize/valid/create-new-env-file/.env.dist: -------------------------------------------------------------------------------- 1 | FOO='bar' 2 | NUMBER=123 3 | BOOLEAN=true -------------------------------------------------------------------------------- /tests/fixtures/actualize/valid/create-new-env-file/.expected: -------------------------------------------------------------------------------- 1 | BOOLEAN=true 2 | FOO='bar' 3 | NUMBER=123 -------------------------------------------------------------------------------- /tests/fixtures/actualize/valid/do-not-delete-old-variable/.env: -------------------------------------------------------------------------------- 1 | FOO='bar' 2 | SOME_VARIABLE='old' 3 | -------------------------------------------------------------------------------- /tests/fixtures/actualize/valid/do-not-delete-old-variable/.env.dist: -------------------------------------------------------------------------------- 1 | FOO='bar' -------------------------------------------------------------------------------- /tests/fixtures/actualize/valid/do-not-delete-old-variable/.expected: -------------------------------------------------------------------------------- 1 | FOO='bar' 2 | SOME_VARIABLE='old' -------------------------------------------------------------------------------- /tests/fixtures/actualize/valid/do-not-replace-old-variable/.env: -------------------------------------------------------------------------------- 1 | FOO='old' -------------------------------------------------------------------------------- /tests/fixtures/actualize/valid/do-not-replace-old-variable/.env.dist: -------------------------------------------------------------------------------- 1 | FOO='bar' -------------------------------------------------------------------------------- /tests/fixtures/actualize/valid/do-not-replace-old-variable/.expected: -------------------------------------------------------------------------------- 1 | FOO='old' -------------------------------------------------------------------------------- /tests/fixtures/actualize/valid/remove-comments/.env: -------------------------------------------------------------------------------- 1 | FOO='bar' -------------------------------------------------------------------------------- /tests/fixtures/actualize/valid/remove-comments/.env.dist: -------------------------------------------------------------------------------- 1 | # Head comment 2 | 3 | FOO= 'bar' #Line comment 4 | 5 | #Another comment 6 | # ENABLED=true -------------------------------------------------------------------------------- /tests/fixtures/actualize/valid/remove-comments/.expected: -------------------------------------------------------------------------------- 1 | FOO='bar' -------------------------------------------------------------------------------- /tests/fixtures/actualize/valid/trim-spaces/.env: -------------------------------------------------------------------------------- 1 | FOO='bar' -------------------------------------------------------------------------------- /tests/fixtures/actualize/valid/trim-spaces/.env.dist: -------------------------------------------------------------------------------- 1 | FOO= 'bar' 2 | 3 | APPEND = 'new line' -------------------------------------------------------------------------------- /tests/fixtures/actualize/valid/trim-spaces/.expected: -------------------------------------------------------------------------------- 1 | APPEND='new line' 2 | FOO='bar' -------------------------------------------------------------------------------- /tests/fixtures/difference/invalid/dist-not-found/error.txt: -------------------------------------------------------------------------------- 1 | The file "fixtures/difference/invalid/dist-not-found/.env.dist" does not exist -------------------------------------------------------------------------------- /tests/fixtures/difference/invalid/invalid-delimiter/.env.dist: -------------------------------------------------------------------------------- 1 | FOO:'bar' -------------------------------------------------------------------------------- /tests/fixtures/difference/invalid/invalid-delimiter/error.txt: -------------------------------------------------------------------------------- 1 | Parse error at 1 line: `FOO:'bar'` is not valid env value -------------------------------------------------------------------------------- /tests/fixtures/difference/invalid/invalid-string/.env.dist: -------------------------------------------------------------------------------- 1 | this is not a valid env variable -------------------------------------------------------------------------------- /tests/fixtures/difference/invalid/invalid-string/error.txt: -------------------------------------------------------------------------------- 1 | Parse error at 1 line: `this is not a valid env variable` is not valid env value -------------------------------------------------------------------------------- /tests/fixtures/difference/invalid/target-not-found/.env.dist: -------------------------------------------------------------------------------- 1 | FOO='bar' -------------------------------------------------------------------------------- /tests/fixtures/difference/invalid/target-not-found/error.txt: -------------------------------------------------------------------------------- 1 | The file "fixtures/difference/invalid/target-not-found/.env" does not exist -------------------------------------------------------------------------------- /tests/fixtures/difference/valid/changed-values/.env: -------------------------------------------------------------------------------- 1 | FOO='bar' 2 | APPEND='new' 3 | -------------------------------------------------------------------------------- /tests/fixtures/difference/valid/changed-values/.env.dist: -------------------------------------------------------------------------------- 1 | FOO='bar' 2 | APPEND='new line' -------------------------------------------------------------------------------- /tests/fixtures/difference/valid/changed-values/expected.log: -------------------------------------------------------------------------------- 1 | Diff between ".env" and ".env.dist" files: 2 | 3 | @ APPEND='new' ('new line') -------------------------------------------------------------------------------- /tests/fixtures/difference/valid/extra-values/.env: -------------------------------------------------------------------------------- 1 | FOO='bar' 2 | APPEND='new line' 3 | EXTRA=true -------------------------------------------------------------------------------- /tests/fixtures/difference/valid/extra-values/.env.dist: -------------------------------------------------------------------------------- 1 | FOO='bar' 2 | APPEND='new line' -------------------------------------------------------------------------------- /tests/fixtures/difference/valid/extra-values/expected.log: -------------------------------------------------------------------------------- 1 | Diff between ".env" and ".env.dist" files: 2 | 3 | + EXTRA=true -------------------------------------------------------------------------------- /tests/fixtures/difference/valid/identical/.env: -------------------------------------------------------------------------------- 1 | APPEND='new line' 2 | FOO='bar' -------------------------------------------------------------------------------- /tests/fixtures/difference/valid/identical/.env.dist: -------------------------------------------------------------------------------- 1 | FOO='bar' 2 | APPEND='new line' -------------------------------------------------------------------------------- /tests/fixtures/difference/valid/identical/expected.log: -------------------------------------------------------------------------------- 1 | ".env" and ".env.dist" is identical -------------------------------------------------------------------------------- /tests/fixtures/difference/valid/missed-values/.env: -------------------------------------------------------------------------------- 1 | FOO='bar' 2 | -------------------------------------------------------------------------------- /tests/fixtures/difference/valid/missed-values/.env.dist: -------------------------------------------------------------------------------- 1 | FOO='bar' 2 | APPEND='new line' -------------------------------------------------------------------------------- /tests/fixtures/difference/valid/missed-values/expected.log: -------------------------------------------------------------------------------- 1 | Diff between ".env" and ".env.dist" files: 2 | 3 | - APPEND='new line' -------------------------------------------------------------------------------- /tests/fixtures/difference/valid/mixed/.env: -------------------------------------------------------------------------------- 1 | FOO='bar' 2 | APPEND='new' 3 | EXTRA=true -------------------------------------------------------------------------------- /tests/fixtures/difference/valid/mixed/.env.dist: -------------------------------------------------------------------------------- 1 | FOO='bar' 2 | APPEND='new line' 3 | MISSED=true -------------------------------------------------------------------------------- /tests/fixtures/difference/valid/mixed/expected.log: -------------------------------------------------------------------------------- 1 | Diff between ".env" and ".env.dist" files: 2 | 3 | - MISSED=true 4 | + EXTRA=true 5 | @ APPEND='new' ('new line') --------------------------------------------------------------------------------