diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..987e2a2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +composer.lock +vendor diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..9a77d05 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,30 @@ +language: php + +sudo: false + +php: + - 7.0 + - 7.1 + +env: + global: + - setup=basic + - coverage=no + +cache: + directories: + - $HOME/.composer/cache/files + +before_script: + - composer config discard-changes true + - if [[ $setup = 'basic' ]]; then travis_retry composer install --prefer-dist --no-interaction; fi + - if [[ $setup = 'stable' ]]; then travis_retry composer update --prefer-dist --no-interaction --prefer-stable; fi + - if [[ $setup = 'lowest' ]]; then travis_retry composer update --prefer-dist --no-interaction --prefer-lowest --prefer-stable; fi + - if [[ $setup = 'coveralls' ]]; then travis_retry composer require "satooshi/php-coveralls=~0.7" --prefer-dist --no-interaction --dev; fi + +script: + - if [[ $coverage = 'yes' ]]; then ./vendor/bin/phpunit -c phpunit.xml --coverage-clover build/logs/clover.xml; fi + - if [[ $coverage = 'no' ]]; then ./vendor/bin/phpunit -c phpunit.xml; fi + +after_script: + - if [[ $setup = 'coveralls' ]]; then php vendor/bin/coveralls -v; fi diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d2ec0a..290d1c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). -## 0.0.1 - 2017-02-07 -### Added +## [1.1.0](https://github.com/superhelio/commands/tree/2.0.0) (2017-08-27) +- New command: `superhelio:gozer` with tests + +## [1.0.0](https://github.com/superhelio/commands/tree/1.0.0) (2017-02-08) +- Fixed Scrutinizer reported issue +- Renamed LICENSE +- Tested `github_changelog_generator`, but did not like it + +## [0.0.1](https://github.com/superhelio/commands/tree/0.0.1) (2017-02-07) - `superhelio:reload` diff --git a/README.md b/README.md index de752e2..545a785 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,9 @@ public function register() ## Usage +- *superhelio:gozer* + - Force delete database tables that has your table prefix + - `php artisan superhelio:gozer` - *superhelio:reload* - Reset database, migrate and seed - `php artisan superhelio:reload` @@ -47,10 +50,6 @@ Please see [CHANGELOG](CHANGELOG.md) for more information what has changed recen $ composer test ``` -## Contributing - -Please see [CONTRIBUTING](CONTRIBUTING.md) for details. - ## Security If you discover any security related issues, please contact [SuperHelio](link-author). @@ -77,4 +76,4 @@ The MIT License (MIT). Please see [License File](LICENSE.md) for more informatio [link-code-quality]: https://scrutinizer-ci.com/g/superhelio/commands [link-downloads]: https://packagist.org/packages/superhelio/commands [link-author]: https://github.com/superhelio -[link-contributors]: ../../contributors +[link-contributors]: https://github.com/superhelio/commands/graphs/contributors diff --git a/composer.json b/composer.json index d827076..227ad04 100644 --- a/composer.json +++ b/composer.json @@ -21,7 +21,9 @@ "illuminate/support": "~5.2" }, "require-dev": { - "phpunit/phpunit" : "4.*" + "phpunit/phpunit" : "4.*", + "orchestra/testbench": "~3.0", + "doctrine/dbal": "~2.3" }, "autoload": { "psr-4": { @@ -30,7 +32,7 @@ }, "autoload-dev": { "psr-4": { - "Superhelio\\Commands\\Test\\": "tests" + "Superhelio\\Commands\\Tests\\": "tests" } }, "scripts": { diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..11092a5 --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,27 @@ + + + + + + ./tests/ + + + + + + + + + src/ + + + \ No newline at end of file diff --git a/src/Commands/Gozer.php b/src/Commands/Gozer.php new file mode 100644 index 0000000..18c485b --- /dev/null +++ b/src/Commands/Gozer.php @@ -0,0 +1,201 @@ +error('You are missing doctrine/dbal, you should add it to your project:'); + $this->info('composer require doctrine/dbal'); + + return false; + } + + $this->info(' + + ________ + / _____/ ____________ ___________ +/ \ ___ / _ \___ // __ \_ __ \ +\ \_\ ( <_> ) /\ ___/| | \/ + \______ /\____/_____ \\___ >__| + \/ \/ \/ + +'); + + $this->setDatabasePrefix($this->getDatabasePrefix()); + + $confirmationQuestion = 'Delete all of your database tables?'; + if (!empty($this->dbPrefix)) { + $confirmationQuestion = sprintf( + 'Delete your tables that begin with %s*', + $this->dbPrefix + ); + } + + if ($this->confirm($confirmationQuestion)) { + $connection = $this->getConnection(); + $tables = $this->getTables($connection); + + /** + * Reject tables that do not have specified table prefix. + * We would not want to destroy other tables that might + * be in the same database, in "homestead" for example. + * + * @var \Illuminate\Support\Collection $tables + */ + $tables = $this->getFilteredTables($tables); + + /** + * Check that we got at least one table, bail out if not + */ + if ($tables->count() < 1) { + $this->info('There are no tables, only Zuul.'); + return true; + } + + /** + * Bid your farewells to these tables. + * Last look and confirmation. + */ + $this->info(sprintf( + "Tables found:\n - %s", + implode(",\n - ", $tables->toArray()) + )); + $this->line(''); + + /** + * Last confirmation before dropping tables + */ + if ($this->confirm('Really delete those tables?')) { + + /** Fancy pants progress bar to see your tables get destroyed */ + $bar = $this->output->createProgressBar($tables->count()); + + Schema::disableForeignKeyConstraints(); + $tables->each(function ($table) use ($bar, $connection) { + + /** Drop the table */ + $connection->dropTable($table); + + /** Advance our progress bar */ + $bar->advance(); + + }); + Schema::enableForeignKeyConstraints(); + + /** Progress bar is now finished */ + $bar->finish(); + } + + $this->line(''); + $this->line(''); + } + + $this->info('Done.'); + + return true; + } + + /** + * @return bool|\Doctrine\DBAL\Schema\AbstractSchemaManager + */ + public function getConnection() + { + try { + /** @var \Doctrine\DBAL\Schema\AbstractSchemaManager $connection */ + $connection = app('db')->connection()->getDoctrineSchemaManager(); + } catch (\Exception $e) { + $this->error($e->getMessage()); + + return false; + } + + return $connection; + } + + /** + * @param \Doctrine\DBAL\Schema\AbstractSchemaManager $connection + * + * @return array|bool + */ + public function getTables(\Doctrine\DBAL\Schema\AbstractSchemaManager $connection) + { + try { + /** @var array $tables */ + $tables = $connection->listTableNames(); + } catch (\Exception $e) { + $this->error($e->getMessage()); + + return false; + } + + return $tables; + } + + public function getDatabasePrefix() + { + return trim(DB::getTablePrefix()); + } + + /** + * This is mainly for testing purposes + * + * @param string $prefix + */ + public function setDatabasePrefix($prefix = '') + { + $this->dbPrefix = $prefix; + } + + /** + * @param array $tables + * + * @return \Illuminate\Support\Collection + */ + public function getFilteredTables($tables = []) + { + $prefix = $this->dbPrefix; + + return collect($tables)->reject(function ($table) use ($prefix) { + return !starts_with($table, $prefix); + }); + } +} diff --git a/src/Commands/Reload.php b/src/Commands/Reload.php index ab29c5a..9b8d8e4 100644 --- a/src/Commands/Reload.php +++ b/src/Commands/Reload.php @@ -18,7 +18,7 @@ class Reload extends Command * * @var string */ - protected $description = 'Delete database tables, migrate and run seeds'; + protected $description = 'Rollback migrations, migrate and run seeds'; /** * Create a new command instance. diff --git a/src/ServiceProvider.php b/src/ServiceProvider.php index c60e155..52f0715 100644 --- a/src/ServiceProvider.php +++ b/src/ServiceProvider.php @@ -30,6 +30,7 @@ class ServiceProvider extends BaseServiceProvider public function register() { $this->registerReloader(); + $this->registerGozer(); } private function registerReloader() @@ -39,4 +40,12 @@ class ServiceProvider extends BaseServiceProvider }); $this->commands('command.superhelio.reload'); } + + private function registerGozer() + { + $this->app->singleton('command.superhelio.gozer', function ($app) { + return $app['Superhelio\Commands\Commands\Gozer']; + }); + $this->commands('command.superhelio.gozer'); + } } diff --git a/tests/GozerTest.php b/tests/GozerTest.php new file mode 100644 index 0000000..449f6a7 --- /dev/null +++ b/tests/GozerTest.php @@ -0,0 +1,131 @@ +artisan('migrate', ['--database' => 'testbench']); + } + + /** + * Define environment setup. + * + * @param \Illuminate\Foundation\Application $app + * + * @return void + */ + protected function getEnvironmentSetUp($app) + { + // Setup default database to use sqlite :memory: + $app['config']->set('database.default', 'testbench'); + $app['config']->set('database.connections.testbench', [ + 'driver' => 'sqlite', + 'database' => ':memory:', + 'prefix' => 'gozerTest__', + ]); + } + + /** + * Get package providers. + * At a minimum this is the package being tested, but also + * would include packages upon which our package depends. + * In a normal app environment these would be added to + * the 'providers' array in the config/app.php file. + * + * @param \Illuminate\Foundation\Application $app + * + * @return array + */ + protected function getPackageProviders($app) + { + return [ + '\Superhelio\Commands\Tests\Stubs\ServiceProvider', + '\Superhelio\Commands\ServiceProvider' + ]; + } + + public function test_database_is_there_and_functions() + { + DB::table('users')->insert([ + 'name' => 'User name', + 'email' => 'hello@gozer.dev', + 'password' => bcrypt('123') + ]); + + $users = DB::table('users')->where('id', '=', 1)->first(); + $this->assertEquals('hello@gozer.dev', $users->email); + $this->assertEquals('User name', $users->name); + $this->assertTrue(Hash::check('123', $users->password)); + } + + public function test_dbal_is_installed() + { + $this->assertTrue(class_exists('\\Doctrine\\DBAL\\Schema\\Schema')); + } + + public function test_gozer_is_installed() + { + $this->assertTrue(class_exists('\\Superhelio\\Commands\\Commands\\Gozer')); + } + + public function test_gozer_has_required_methods_and_properties() + { + $gozer = new ReflectionClass('\\Superhelio\\Commands\\Commands\\Gozer'); + $this->assertTrue($gozer->hasMethod('handle')); + $this->assertTrue($gozer->hasProperty('signature')); + $this->assertTrue($gozer->hasProperty('description')); + $this->assertTrue($gozer->hasProperty('dbPrefix')); + } + + public function test_gozer_finds_database_prefix() + { + $gozer = new Gozer(); + + $this->assertEquals('gozerTest__', $gozer->getDatabasePrefix()); + } + + public function test_gozer_finds_users_table() + { + $gozer = new Gozer(); + + $connection = $gozer->getConnection(); + + $tables = $gozer->getTables($connection); + $this->assertTrue(in_array('gozerTest__users', $tables, false)); + + $gozer->setDatabasePrefix('gozerTest__'); + $filteredTables = $gozer->getFilteredTables($tables); + $this->assertTrue(is_a($filteredTables, \Illuminate\Support\Collection::class)); + $this->assertTrue(in_array('gozerTest__users', $filteredTables->toArray(), false)); + } + + public function test_gozer_table_filtering_works() + { + $gozer = new Gozer(); + $tables = array( + 'gozerTest__users', + 'gozerTest__migrations', + 'this_should_be_filtered', + 'filter_me_too' + ); + + $gozer->setDatabasePrefix('gozerTest__'); + $filtered = $gozer->getFilteredTables($tables); + $array = $filtered->toArray(); + + $this->assertFalse(in_array('this_should_be_filtered', $array, false)); + $this->assertFalse(in_array('filter_me_too', $array, false)); + $this->assertTrue(in_array('gozerTest__users', $array, false)); + $this->assertTrue(in_array('gozerTest__migrations', $array, false)); + } +} diff --git a/tests/ReloadTest.php b/tests/ReloadTest.php new file mode 100644 index 0000000..23d97e0 --- /dev/null +++ b/tests/ReloadTest.php @@ -0,0 +1,14 @@ +assertTrue(true); + } +} diff --git a/tests/Stubs/ServiceProvider.php b/tests/Stubs/ServiceProvider.php new file mode 100644 index 0000000..6a65aa8 --- /dev/null +++ b/tests/Stubs/ServiceProvider.php @@ -0,0 +1,10 @@ +loadMigrationsFrom(realpath(__DIR__ . '/../migrations')); + } +} diff --git a/tests/migrations/2014_10_12_000000_create_users_table.php b/tests/migrations/2014_10_12_000000_create_users_table.php new file mode 100644 index 0000000..689cbee --- /dev/null +++ b/tests/migrations/2014_10_12_000000_create_users_table.php @@ -0,0 +1,35 @@ +increments('id'); + $table->string('name'); + $table->string('email')->unique(); + $table->string('password'); + $table->rememberToken(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('users'); + } +}