├── .gitattributes ├── .gitignore ├── .php_cs ├── .travis.yml ├── ISSUE_TEMPLATE ├── LICENSE ├── README.md ├── composer.json ├── phpunit.xml ├── publishable └── config │ └── hooks.php ├── resources └── logo.png ├── src ├── Commands │ ├── CheckCommand.php │ ├── DisableCommand.php │ ├── EnableCommand.php │ ├── InfoCommand.php │ ├── InstallCommand.php │ ├── ListCommand.php │ ├── MakeCommand.php │ ├── SetupCommand.php │ ├── UninstallCommand.php │ └── UpdateCommand.php ├── Composer.php ├── Events │ ├── DisabledHook.php │ ├── DisablingHook.php │ ├── EnabledHook.php │ ├── EnablingHook.php │ ├── InstalledHook.php │ ├── InstallingHook.php │ ├── MadeHook.php │ ├── MakingHook.php │ ├── Setup.php │ ├── UninstalledHook.php │ ├── UninstallingHook.php │ ├── UpdatedHook.php │ ├── UpdatesAvailableForHook.php │ └── UpdatingHook.php ├── Exceptions │ ├── HookAlreadyEnabledException.php │ ├── HookAlreadyExistsException.php │ ├── HookAlreadyInstalledException.php │ ├── HookException.php │ ├── HookNotEnabledException.php │ ├── HookNotFoundException.php │ └── HookNotInstalledException.php ├── Hook.php ├── Hooks.php ├── HooksFacade.php ├── HooksServiceProvider.php └── Migrator.php ├── stub ├── composer.json ├── resources │ ├── assets │ │ └── scripts │ │ │ └── alert.js │ └── database │ │ ├── migrations │ │ ├── .gitkeep │ │ └── MIGRATION_DATE_TIME_create_snake_case_table.php │ │ ├── seeders │ │ ├── .gitkeep │ │ └── StudlyCaseTableSeeder.php │ │ └── unseeders │ │ ├── .gitkeep │ │ └── StudlyCaseTableUnseeder.php └── src │ ├── StudlyCase.php │ ├── StudlyCaseFacade.php │ └── StudlyCaseServiceProvider.php └── tests ├── HooksTest.php ├── TestCase.php ├── bootstrap.php └── fixtures ├── composer.json ├── resources ├── assets │ └── scripts │ │ └── alert.js └── database │ ├── migrations │ ├── .gitkeep │ └── 2018_01_20_120000_create_local_test_hook_table.php │ ├── seeders │ ├── .gitkeep │ └── LocalTestHookTableSeeder.php │ └── unseeders │ ├── .gitkeep │ └── LocalTestHookTableUnseeder.php └── src ├── LocalTestHook.php ├── LocalTestHookFacade.php └── LocalTestHookServiceProvider.php /.gitattributes: -------------------------------------------------------------------------------- 1 | *.php linguist-language=PHP 2 | *.js linguist-language=PHP -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | vendor/ 2 | build/ 3 | composer.lock -------------------------------------------------------------------------------- /.php_cs: -------------------------------------------------------------------------------- 1 | finder(DefaultFinder::create()->in(__DIR__)) 75 | ->fixers($fixers) 76 | ->level(FixerInterface::NONE_LEVEL) 77 | ->setUsingCache(true); 78 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 7.2 5 | - 7.3 6 | - 7.4 7 | - nightly 8 | 9 | matrix: 10 | allow_failures: 11 | - php: nightly 12 | 13 | services: 14 | - sqlite 15 | 16 | before_script: 17 | - composer install 18 | - travis_retry composer self-update 19 | - travis_retry composer update ${COMPOSER_FLAGS} --no-interaction --prefer-dist 20 | 21 | script: 22 | - vendor/bin/phpunit --no-coverage 23 | -------------------------------------------------------------------------------- /ISSUE_TEMPLATE: -------------------------------------------------------------------------------- 1 | - Hooks Version: #.#.# 2 | - Laravel Version: #.#.# 3 | - PHP Version: 4 | 5 | ### Description: 6 | 7 | 8 | ### Steps To Reproduce: 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Larapack 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Hooks](https://raw.githubusercontent.com/larapack/hooks/master/resources/logo.png) 2 | 3 |

4 | Build Status 5 | Build Status 6 | Total Downloads 7 | Latest Stable Version 8 | License 9 |

10 | 11 | Made with ❤️ by [Mark Topper](https://marktopper.com) 12 | 13 | # Hooks 14 | 15 | Hooks is a extension system for your [Laravel](https://laravel.com) application. 16 | 17 | # Installation 18 | 19 | Install using composer: 20 | 21 | ``` 22 | composer require larapack/hooks 23 | ``` 24 | 25 | Then add the service provider to the configuration: 26 | ```php 27 | 'providers' => [ 28 | Larapack\Hooks\HooksServiceProvider::class, 29 | ], 30 | ``` 31 | 32 | # Packages 33 | 34 | Packages can be found on [larapack.io](https://larapack.io). 35 | 36 | # Integrations 37 | 38 | - [Voyager Hooks](https://github.com/larapack/voyager-hooks) - Hooks supported directly in the Voyager admin panel. 39 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "larapack/hooks", 3 | "description": "A Laravel Hook system", 4 | "keywords": ["laravel", "hooks"], 5 | "license": "MIT", 6 | "homepage": "https://larapack.io/", 7 | "support": { 8 | "issues": "https://github.com/larapack/hooks/issues", 9 | "source": "https://github.com/larapack/hooks" 10 | }, 11 | "authors": [ 12 | { 13 | "name": "Mark Topper", 14 | "email": "mark@ulties.com" 15 | } 16 | ], 17 | "require": { 18 | "composer/composer": ">=1.4" 19 | }, 20 | "require-dev": { 21 | "orchestra/testbench": ">=3.0", 22 | "phpunit/phpunit": ">=5.6" 23 | }, 24 | "autoload": { 25 | "psr-4": { 26 | "Larapack\\Hooks\\": "src/" 27 | } 28 | }, 29 | "autoload-dev": { 30 | "psr-4": { 31 | "Larapack\\Hooks\\Tests\\": "tests/" 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 14 | 15 | 16 | tests 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /publishable/config/hooks.php: -------------------------------------------------------------------------------- 1 | env('HOOKS_ENABLED', true), 6 | 7 | ]; 8 | -------------------------------------------------------------------------------- /resources/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/larapack/hooks/ce2c8c078a56036c357f26036174412cb9059f8e/resources/logo.png -------------------------------------------------------------------------------- /src/Commands/CheckCommand.php: -------------------------------------------------------------------------------- 1 | hooks = $hooks; 19 | 20 | parent::__construct(); 21 | } 22 | 23 | public function fire() 24 | { 25 | return $this->handle(); 26 | } 27 | 28 | public function handle() 29 | { 30 | $hooks = $this->hooks->checkForUpdates(); 31 | 32 | $count = $hooks->count(); 33 | 34 | $this->info(($count == 1 ? '1 update' : $count.' updates').' available.'); 35 | 36 | foreach ($hooks as $hook) { 37 | $this->comment($hook->name.' '.$hook->version); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Commands/DisableCommand.php: -------------------------------------------------------------------------------- 1 | hooks = $hooks; 19 | 20 | parent::__construct(); 21 | } 22 | 23 | public function fire() 24 | { 25 | return $this->handle(); 26 | } 27 | 28 | public function handle() 29 | { 30 | $name = $this->argument('name'); 31 | 32 | $this->hooks->disable($name); 33 | 34 | $this->info("Hook [{$name}] has been disabled."); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Commands/EnableCommand.php: -------------------------------------------------------------------------------- 1 | hooks = $hooks; 19 | 20 | parent::__construct(); 21 | } 22 | 23 | public function fire() 24 | { 25 | return $this->handle(); 26 | } 27 | 28 | public function handle() 29 | { 30 | $name = $this->argument('name'); 31 | 32 | $this->hooks->enable($name); 33 | 34 | $this->info("Hook [{$name}] has been enabled."); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Commands/InfoCommand.php: -------------------------------------------------------------------------------- 1 | hooks = $hooks; 19 | 20 | parent::__construct(); 21 | } 22 | 23 | public function fire() 24 | { 25 | return $this->handle(); 26 | } 27 | 28 | public function handle() 29 | { 30 | $name = $this->argument('name'); 31 | 32 | $hook = $this->hooks->hooks()->where('name', $name)->first(); 33 | 34 | if (is_null($hook)) { 35 | return $this->error("Hook [{$name}] not found."); 36 | } 37 | 38 | $this->comment($name); 39 | $this->line(" Name: {$name}"); 40 | $this->line(' Status: '.($hook['enabled'] ? 'Enabled' : 'Disabled')); 41 | $this->line(' Version: '.(!is_null($hook['version']) ? $hook['version'] : 'None')); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Commands/InstallCommand.php: -------------------------------------------------------------------------------- 1 | hooks = $hooks; 19 | 20 | parent::__construct(); 21 | } 22 | 23 | public function fire() 24 | { 25 | return $this->handle(); 26 | } 27 | 28 | public function handle() 29 | { 30 | $name = $this->argument('name'); 31 | 32 | $this->hooks->install( 33 | $name, 34 | $this->argument('version'), 35 | !$this->option('no-migrate'), 36 | !$this->option('no-seed'), 37 | !$this->option('no-publish') 38 | ); 39 | 40 | if ($this->option('enable')) { 41 | $this->hooks->enable($name); 42 | 43 | $this->info("Hook [{$name}] has been installed and enabled."); 44 | } else { 45 | $this->info("Hook [{$name}] has been installed."); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Commands/ListCommand.php: -------------------------------------------------------------------------------- 1 | hooks = $hooks; 19 | 20 | parent::__construct(); 21 | } 22 | 23 | public function fire() 24 | { 25 | return $this->handle(); 26 | } 27 | 28 | public function handle() 29 | { 30 | $this->table(['Name', 'Status'], $this->hooks->hooks()->transform(function ($hook) { 31 | return [ 32 | 'name' => $hook['name'], 33 | 'enabled' => $hook['enabled'] ? 'Enabled' : 'Disabled', 34 | ]; 35 | })); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Commands/MakeCommand.php: -------------------------------------------------------------------------------- 1 | hooks = $hooks; 20 | 21 | parent::__construct(); 22 | } 23 | 24 | public function fire() 25 | { 26 | return $this->handle(); 27 | } 28 | 29 | public function handle() 30 | { 31 | $name = $this->argument('name'); 32 | $name = Str::kebab($name); 33 | 34 | $this->hooks->make($name); 35 | 36 | $this->info("Hook [{$name}] has been made."); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Commands/SetupCommand.php: -------------------------------------------------------------------------------- 1 | filesystem = $filesystem; 25 | 26 | parent::__construct(); 27 | } 28 | 29 | public function fire() 30 | { 31 | return $this->handle(); 32 | } 33 | 34 | public function handle() 35 | { 36 | $composer = new Composer(base_path('composer.json')); 37 | 38 | $composer->addRepository(static::REPOSITORY_NAME, [ 39 | 'type' => 'composer', 40 | 'url' => $this->option('url'), 41 | ]); 42 | 43 | if (Str::startsWith($this->option('url'), 'http://')) { 44 | $composer->addConfig('secure-http', false); 45 | } 46 | 47 | $composer->save(); 48 | 49 | $this->call('vendor:publish', ['--provider' => HooksServiceProvider::class]); 50 | 51 | $this->info('Hooks are now ready to use! Go ahead and try to "php artisan hook:install test-hook"'); 52 | 53 | event(new Setup()); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/Commands/UninstallCommand.php: -------------------------------------------------------------------------------- 1 | hooks = $hooks; 19 | 20 | parent::__construct(); 21 | } 22 | 23 | public function fire() 24 | { 25 | return $this->handle(); 26 | } 27 | 28 | public function handle() 29 | { 30 | $name = $this->argument('name'); 31 | 32 | $this->hooks->uninstall( 33 | $name, 34 | $this->option('delete'), 35 | !$this->option('no-unmigrate'), 36 | !$this->option('no-unseed'), 37 | !$this->option('no-unpublish') 38 | ); 39 | 40 | $this->info("Hook [{$name}] has been uninstalled."); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Commands/UpdateCommand.php: -------------------------------------------------------------------------------- 1 | hooks = $hooks; 19 | 20 | parent::__construct(); 21 | } 22 | 23 | public function fire() 24 | { 25 | return $this->handle(); 26 | } 27 | 28 | public function handle() 29 | { 30 | $name = $this->argument('name'); 31 | 32 | $hooks = $this->hooks->hooks(); 33 | 34 | $version = $this->argument('version'); 35 | 36 | $hook = $hooks->where('name', $name)->first(); 37 | 38 | $updated = $this->hooks->update( 39 | $name, 40 | $version, 41 | !$this->option('no-migrate'), 42 | !$this->option('no-seed'), 43 | !$this->option('no-publish'), 44 | $this->option('force') 45 | ); 46 | 47 | return $updated 48 | ? $this->info("Hook [{$name}] has been updated!") 49 | : $this->info('Nothing to update.'); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/Composer.php: -------------------------------------------------------------------------------- 1 | filesystem = app(Filesystem::class); 22 | $this->location = $location; 23 | 24 | $this->read(); 25 | } 26 | 27 | public function addRepository($name, $info) 28 | { 29 | if (!$this->items->has('repositories')) { 30 | $this->items['repositories'] = []; 31 | } 32 | 33 | $this->items->set('repositories.'.$name, $info); 34 | 35 | $this->changed = true; 36 | 37 | return $this; 38 | } 39 | 40 | public function addConfig($key, $value) 41 | { 42 | if (!$this->items->has('config')) { 43 | $this->items['config'] = []; 44 | } 45 | 46 | $this->items->set('config.'.$key, $value); 47 | 48 | $this->changed = true; 49 | 50 | return $this; 51 | } 52 | 53 | public function set($key, $value) 54 | { 55 | $this->items->set($key, $value); 56 | 57 | $this->changed = true; 58 | 59 | return $this; 60 | } 61 | 62 | public function get($key, $default = null) 63 | { 64 | return $this->items->get($key, $default); 65 | } 66 | 67 | public function has($key) 68 | { 69 | return $this->items->has($key); 70 | } 71 | 72 | public function save() 73 | { 74 | if ($this->changed) { 75 | $this->filesystem->put($this->location, $this->encode($this->items->all())); 76 | 77 | $this->changed = false; 78 | } 79 | } 80 | 81 | protected function read() 82 | { 83 | $this->items = new Repository($this->decode( 84 | $this->filesystem->get($this->location) 85 | )); 86 | 87 | $this->changed = false; 88 | } 89 | 90 | protected function decode($string) 91 | { 92 | return json_decode($string, true); 93 | } 94 | 95 | protected function encode(array $array) 96 | { 97 | return json_encode($array, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/Events/DisabledHook.php: -------------------------------------------------------------------------------- 1 | hook = $hook; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Events/DisablingHook.php: -------------------------------------------------------------------------------- 1 | hook = $hook; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Events/EnabledHook.php: -------------------------------------------------------------------------------- 1 | hook = $hook; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Events/EnablingHook.php: -------------------------------------------------------------------------------- 1 | hook = $hook; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Events/InstalledHook.php: -------------------------------------------------------------------------------- 1 | hook = $hook; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Events/InstallingHook.php: -------------------------------------------------------------------------------- 1 | hook = $hook; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Events/MadeHook.php: -------------------------------------------------------------------------------- 1 | hook = $hook; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Events/MakingHook.php: -------------------------------------------------------------------------------- 1 | hook = $hook; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Events/Setup.php: -------------------------------------------------------------------------------- 1 | hook = $hook; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Events/UninstallingHook.php: -------------------------------------------------------------------------------- 1 | hook = $hook; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Events/UpdatedHook.php: -------------------------------------------------------------------------------- 1 | hook = $hook; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Events/UpdatesAvailableForHook.php: -------------------------------------------------------------------------------- 1 | hook = $hook; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Events/UpdatingHook.php: -------------------------------------------------------------------------------- 1 | hook = $hook; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Exceptions/HookAlreadyEnabledException.php: -------------------------------------------------------------------------------- 1 | filesystem = new Filesystem(); 29 | 30 | $this->update($data); 31 | 32 | $this->loadJson(); 33 | } 34 | 35 | public function getProviders() 36 | { 37 | return $this->getComposerHookKey('providers', []); 38 | } 39 | 40 | public function getComposerHookKey($key, $default = null) 41 | { 42 | if (is_null($this->composerJson)) { 43 | $this->loadComposerJson(); 44 | } 45 | 46 | if (!isset($this->composerJson['extra'])) { 47 | return $default; 48 | } 49 | 50 | if (!isset($this->composerJson['extra']['hook'])) { 51 | return $default; 52 | } 53 | 54 | if (!isset($this->composerJson['extra']['hook'][$key])) { 55 | return $default; 56 | } 57 | 58 | return $this->composerJson['extra']['hook'][$key]; 59 | } 60 | 61 | public function getAliases() 62 | { 63 | return $this->getComposerHookKey('aliases', []); 64 | } 65 | 66 | public function loadComposerJson() 67 | { 68 | $this->composerJson = json_decode($this->getComposerJsonFile(), true); 69 | } 70 | 71 | public function getPath() 72 | { 73 | if ($this->isLocal()) { 74 | return base_path('hooks/'.$this->name); 75 | } 76 | 77 | return base_path('vendor/'.$this->name); 78 | } 79 | 80 | public function getComposerJsonFile() 81 | { 82 | return $this->filesystem->get($this->getPath().'/composer.json'); 83 | } 84 | 85 | public function setLatest($latest) 86 | { 87 | $this->latest = $latest; 88 | } 89 | 90 | public function loadJson($path = null) 91 | { 92 | if (is_null($path)) { 93 | if ($this->isLocal()) { 94 | $path = base_path("hooks/{$this->name}/hook.json"); 95 | } else { 96 | $path = base_path("vendor/{$this->name}/hook.json"); 97 | } 98 | } 99 | 100 | $this->mergeWithJson($path); 101 | } 102 | 103 | public function update(array $parameters) 104 | { 105 | foreach ($parameters as $key => $value) { 106 | $this->setAttribute($key, $value); 107 | } 108 | } 109 | 110 | public function outdated() 111 | { 112 | if (is_null($this->latest)) { 113 | $this->latest = app('hooks')->outdated($this->name); 114 | } 115 | 116 | return $this->latest != $this->version; 117 | } 118 | 119 | public function mergeWithJson($path) 120 | { 121 | if ($this->filesystem->exists($path)) { 122 | $data = json_decode($this->filesystem->get($path), true); 123 | 124 | $this->update( 125 | collect($data)->only(static::$jsonParameters)->all() 126 | ); 127 | } 128 | } 129 | 130 | public function setAttribute($key, $value) 131 | { 132 | $method = Str::camel('set_'.$key.'_attribute'); 133 | 134 | if (method_exists($this, $method)) { 135 | return $this->$method($value); 136 | } 137 | 138 | $this->$key = $value; 139 | } 140 | 141 | public function getAttribute($key) 142 | { 143 | $method = Str::camel('get_'.$key.'_attribute'); 144 | 145 | if (method_exists($this, $method)) { 146 | return $this->$method(); 147 | } 148 | 149 | return $this->$key; 150 | } 151 | 152 | public function offsetExists($offset) 153 | { 154 | return isset($this->$offset); 155 | } 156 | 157 | public function offsetGet($offset) 158 | { 159 | return $this->getAttribute($offset); 160 | } 161 | 162 | public function offsetSet($offset, $value) 163 | { 164 | $this->setAttribute($offset, $value); 165 | } 166 | 167 | public function offsetUnset($offset) 168 | { 169 | unset($this->$offset); 170 | } 171 | 172 | public function __get($key) 173 | { 174 | return $this->getAttribute($key); 175 | } 176 | 177 | public function __set($key, $value) 178 | { 179 | return $this->setAttribute($key, $value); 180 | } 181 | 182 | public function toArray() 183 | { 184 | return [ 185 | 'name' => $this->name, 186 | 'description' => $this->description, 187 | 'version' => $this->version, 188 | 'enabled' => (bool) $this->enabled, 189 | ]; 190 | } 191 | 192 | public function __toArray() 193 | { 194 | return $this->toArray(); 195 | } 196 | 197 | public function isLocal() 198 | { 199 | return $this->filesystem->isDirectory(base_path("hooks/{$this->name}")); 200 | } 201 | } 202 | -------------------------------------------------------------------------------- /src/Hooks.php: -------------------------------------------------------------------------------- 1 | app = Application::getInstance(); 40 | $this->filesystem = $filesystem; 41 | $this->migrator = $migrator; 42 | 43 | $this->prepareComposer(); 44 | $this->readOutdated(); 45 | $this->readJsonFile(); 46 | 47 | $this->composerJson = new Composer(base_path('composer.json')); 48 | 49 | $this->composerOutput[] = new RawOutput(); 50 | 51 | $this->prepareMemoryLimit(); 52 | } 53 | 54 | public static function setUseVersionWildcardOnUpdate($boolean) 55 | { 56 | static::$useVersionWildcardOnUpdate = $boolean; 57 | } 58 | 59 | public static function useVersionWildcardOnUpdate($boolean = true) 60 | { 61 | static::setUseVersionWildcardOnUpdate($boolean); 62 | } 63 | 64 | public static function enableVersionWildcardOnUpdate() 65 | { 66 | static::setUseVersionWildcardOnUpdate(true); 67 | } 68 | 69 | public static function disableVersionWildcardOnUpdate() 70 | { 71 | static::setUseVersionWildcardOnUpdate(false); 72 | } 73 | 74 | public static function getUseVersionWildcardOnUpdate() 75 | { 76 | return static::$useVersionWildcardOnUpdate; 77 | } 78 | 79 | public static function fakeDateTime(Carbon $dateTime) 80 | { 81 | static::$fakeDateTime = $dateTime; 82 | } 83 | 84 | public function readOutdated() 85 | { 86 | $file = base_path('hooks/outdated.json'); 87 | 88 | if ($this->filesystem->exists($file)) { 89 | $this->outdated = json_decode($this->filesystem->get($file), true); 90 | } 91 | } 92 | 93 | protected function memoryInBytes($value) 94 | { 95 | $unit = strtolower(substr($value, -1, 1)); 96 | $value = (int) $value; 97 | 98 | switch ($unit) { 99 | case 'g': 100 | $value *= 1024; 101 | // no break (cumulative multiplier) 102 | case 'm': 103 | $value *= 1024; 104 | // no break (cumulative multiplier) 105 | case 'k': 106 | $value *= 1024; 107 | } 108 | 109 | return $value; 110 | } 111 | 112 | public static function setMemoryLimit($memoryLimit) 113 | { 114 | static::$memoryLimit = $memoryLimit; 115 | 116 | if (static::$memoryLimitSet) { 117 | app(static::class)->prepareMemoryLimit(); 118 | } 119 | } 120 | 121 | public static function getMemoryLimit() 122 | { 123 | return static::$memoryLimit; 124 | } 125 | 126 | public function prepareMemoryLimit() 127 | { 128 | if (!function_exists('ini_set')) { 129 | return; 130 | } 131 | 132 | $memoryLimit = ini_get('memory_limit'); 133 | 134 | // Increase memory_limit if it is lower than 1.5GB 135 | if ($memoryLimit != -1 && $this->memoryInBytes($memoryLimit) < 1024 * 1024 * 1536) { 136 | $memoryLimit = '1536M'; 137 | } 138 | 139 | // Increaes memory_limit if it is lower than the application requirement 140 | if (!is_null(static::$memoryLimit) && $this->memoryInBytes($memoryLimit) < $this->memoryInBytes(static::$memoryLimit)) { 141 | $memoryLimit = static::$memoryLimit; 142 | } 143 | 144 | // Set if not -1 145 | if (static::$memoryLimit != -1) { 146 | @ini_set('memory_limit', $memoryLimit); 147 | } 148 | 149 | static::$memoryLimitSet = true; 150 | } 151 | 152 | public function prepareComposer() 153 | { 154 | // Set environment 155 | //putenv('COMPOSER_BINARY='.realpath($_SERVER['argv'][0])); 156 | 157 | // Prepare Composer Application instance 158 | $this->composer = new \Composer\Console\Application(); 159 | $this->composer->setAutoExit(false); 160 | $this->composer->setCatchExceptions(false); 161 | } 162 | 163 | /** 164 | * Get remote url. 165 | * 166 | * @return string 167 | */ 168 | public static function getRemote() 169 | { 170 | return static::$remote; 171 | } 172 | 173 | /** 174 | * Set remote url. 175 | * 176 | * @param $remote 177 | */ 178 | public static function setRemote($remote) 179 | { 180 | static::$remote = $remote; 181 | } 182 | 183 | public function getLastRemoteCheck() 184 | { 185 | return $this->lastRemoteCheck; 186 | } 187 | 188 | public function setLastRemoteCheck(Carbon $carbon) 189 | { 190 | $this->lastRemoteCheck = $carbon; 191 | } 192 | 193 | /** 194 | * Install hook. 195 | * 196 | * @param $name 197 | * 198 | * @throws \Larapack\Hooks\Exceptions\HookAlreadyInstalledException 199 | */ 200 | public function install($name, $version = null, $migrate = true, $seed = true, $publish = true) 201 | { 202 | // Check if already installed 203 | if ($this->installed($name)) { 204 | throw new Exceptions\HookAlreadyInstalledException("Hook [{$name}] is already installed."); 205 | } 206 | 207 | event(new Events\InstallingHook($name)); 208 | 209 | // Prepare a repository if the hook is located locally 210 | if ($this->local($name)) { 211 | $this->prepareLocalInstallation($name); 212 | 213 | if (is_null($version)) { 214 | $version = static::$localVersion; 215 | } 216 | } 217 | 218 | // Require hook 219 | if (is_null($version)) { 220 | $this->composerRequire([$name]); // TODO: Save Composer output somewhere 221 | } else { 222 | $this->composerRequire([$name.':'.$version]); // TODO: Save Composer output somewhere 223 | } 224 | 225 | // TODO: Handle the case when Composer outputs: 226 | // Your requirements could not be resolved to an installable set of packages. 227 | // 228 | // Problem 1 229 | // - The requested package composer-github-hook v0.0.1 exists as composer-github-hook[dev-master] 230 | // but these are rejected by your constraint. 231 | 232 | // TODO: Move to Composer Plugin 233 | $this->readJsonFile([$name]); 234 | $this->remakeJson(); 235 | 236 | if ($migrate) { 237 | $this->migrateHook($this->hooks[$name]); 238 | } 239 | 240 | if ($seed) { 241 | $this->seedHook($this->hooks[$name]); 242 | } 243 | 244 | if ($publish) { 245 | $this->publishHook($this->hooks[$name]); 246 | } 247 | 248 | event(new Events\InstalledHook($this->hooks[$name])); 249 | } 250 | 251 | public function prepareLocalInstallation($name) 252 | { 253 | $this->composerJson->addRepository($name, [ 254 | 'type' => 'path', 255 | 'url' => "hooks/{$name}", 256 | ]); 257 | 258 | $this->composerJson->save(); 259 | } 260 | 261 | /** 262 | * Uninstall a hook. 263 | * 264 | * @param $name 265 | * @param $keep boolean 266 | * 267 | * @throws \Larapack\Hooks\Exceptions\HookNotInstalledException 268 | */ 269 | public function uninstall($name, $delete = false, $unmigrate = true, $unseed = true, $unpublish = true) 270 | { 271 | // Check if installed 272 | if (!$this->installed($name)) { 273 | throw new Exceptions\HookNotInstalledException("Hook [{$name}] is not installed."); 274 | } 275 | 276 | $hook = $this->hook($name); 277 | 278 | $hook->loadJson(); 279 | 280 | event(new Events\UninstallingHook($hook)); 281 | 282 | if ($this->enabled($name)) { 283 | event(new Events\DisablingHook($hook)); 284 | 285 | // Some logic could later be placed here 286 | 287 | event(new Events\DisabledHook($hook)); 288 | } 289 | 290 | if ($unseed) { 291 | $this->unseedHook($hook); 292 | } 293 | 294 | if ($unmigrate) { 295 | $this->unmigrateHook($hook); 296 | } 297 | 298 | if ($unpublish) { 299 | $this->unpublishHook($hook); 300 | } 301 | 302 | $this->runComposer([ 303 | 'command' => 'remove', 304 | 'packages' => [$name], 305 | ]); 306 | 307 | $hooks = $this->hooks()->where('name', '!=', $name); 308 | $this->hooks = $hooks; 309 | 310 | $this->remakeJson(); 311 | 312 | event(new Events\UninstalledHook($name)); 313 | 314 | if ($delete && $hook->isLocal()) { 315 | $this->filesystem->deleteDirectory(base_path("hooks/{$name}")); 316 | } 317 | } 318 | 319 | /** 320 | * Update hook. 321 | * 322 | * @param $name 323 | * @param string|null $version 324 | * @param bool $migrate 325 | * @param bool $seed 326 | * @param bool $publish 327 | * @param bool $force 328 | * 329 | * @throws \Larapack\Hooks\Exceptions\HookNotFoundException 330 | * @throws \Larapack\Hooks\Exceptions\HookNotInstalledException 331 | * 332 | * @return bool 333 | */ 334 | public function update($name, $version, $migrate = true, $seed = true, $publish = true, $force = false) 335 | { 336 | // Check if hook exists 337 | if (!$this->downloaded($name)) { 338 | throw new Exceptions\HookNotFoundException("Hook [{$name}] not found."); 339 | } 340 | 341 | // Check if installed 342 | if (!$this->installed($name)) { 343 | throw new Exceptions\HookNotInstalledException("Hook [{$name}] not installed."); 344 | } 345 | 346 | event(new Events\UpdatingHook($this->hooks[$name])); 347 | 348 | if (is_null($version)) { 349 | if (static::$useVersionWildcardOnUpdate) { 350 | $version = static::$versionWildcard; 351 | } 352 | 353 | // Prepare a repository if the hook is located locally 354 | if ($this->local($name)) { 355 | $version = static::$localVersion; 356 | } 357 | } 358 | 359 | if (!$force) { 360 | $this->makeTemponaryBackup($this->hooks[$name]); 361 | } 362 | 363 | // Require hook 364 | if (is_null($version)) { 365 | $this->composerRequire([$name]); // TODO: Save Composer output somewhere 366 | } else { 367 | $this->composerRequire([$name.':'.$version]); // TODO: Save Composer output somewhere 368 | } 369 | 370 | // TODO: Handle the case when Composer outputs: 371 | // Your requirements could not be resolved to an installable set of packages. 372 | // 373 | // Problem 1 374 | // - The requested package composer-github-hook v0.0.1 exists as composer-github-hook[dev-master] 375 | // but these are rejected by your constraint. 376 | 377 | // TODO: Move to Composer Plugin 378 | $this->readJsonFile(); 379 | $this->remakeJson(); 380 | 381 | if ($migrate) { 382 | $this->migrateHook($this->hooks[$name]); 383 | } 384 | 385 | if ($seed) { 386 | $this->seedHook($this->hooks[$name]); 387 | } 388 | 389 | if ($publish) { 390 | $this->publishHook($this->hooks[$name], $force); 391 | } 392 | 393 | $this->clearTemponaryFiles(); 394 | 395 | event(new Events\UpdatedHook($this->hooks[$name])); 396 | 397 | return true; 398 | } 399 | 400 | /** 401 | * Enable hook. 402 | * 403 | * @param $name 404 | * 405 | * @throws \Larapack\Hooks\Exceptions\HookNotFoundException 406 | * @throws \Larapack\Hooks\Exceptions\HookNotInstalledException 407 | * @throws \Larapack\Hooks\Exceptions\HookAlreadyEnabledException 408 | */ 409 | public function enable($name) 410 | { 411 | // Check if exists 412 | if (!$this->downloaded($name)) { 413 | throw new Exceptions\HookNotFoundException("Hook [{$name}] not found."); 414 | } 415 | 416 | if (!$this->installed($name)) { 417 | throw new Exceptions\HookNotInstalledException("Hook [{$name}] not installed."); 418 | } 419 | 420 | if ($this->enabled($name)) { 421 | throw new Exceptions\HookAlreadyEnabledException("Hook [{$name}] already enabled."); 422 | } 423 | 424 | $hook = $this->hook($name); 425 | 426 | $hook->loadJson(); 427 | 428 | event(new Events\EnablingHook($hook)); 429 | 430 | $this->hooks[$name]->update(['enabled' => true]); 431 | 432 | $this->remakeJson(); 433 | 434 | event(new Events\EnabledHook($hook)); 435 | } 436 | 437 | /** 438 | * Disable a hook. 439 | * 440 | * @param $name 441 | * 442 | * @throws \Larapack\Hooks\Exceptions\HookNotFoundException 443 | * @throws \Larapack\Hooks\Exceptions\HookNotEnabledException 444 | * @throws \Larapack\Hooks\Exceptions\HookNotInstalledException 445 | */ 446 | public function disable($name) 447 | { 448 | // Check if exists 449 | if (!$this->downloaded($name)) { 450 | throw new Exceptions\HookNotFoundException("Hook [{$name}] not found."); 451 | } 452 | 453 | if (!$this->installed($name)) { 454 | throw new Exceptions\HookNotInstalledException("Hook [{$name}] not installed."); 455 | } 456 | 457 | if (!$this->enabled($name)) { 458 | throw new Exceptions\HookNotEnabledException("Hook [{$name}] not enabled."); 459 | } 460 | 461 | $hook = $this->hook($name); 462 | 463 | $hook->loadJson(); 464 | 465 | event(new Events\DisablingHook($hook)); 466 | 467 | $this->hooks[$name]->update(['enabled' => false]); 468 | 469 | $this->remakeJson(); 470 | 471 | event(new Events\DisabledHook($hook)); 472 | } 473 | 474 | /** 475 | * Make hook. 476 | * 477 | * @param $name 478 | * 479 | * @throws \Larapack\Hooks\Exceptions\HookAlreadyExistsException 480 | */ 481 | public function make($name) 482 | { 483 | $studlyCase = Str::studly($name); 484 | 485 | // Check if already exists 486 | if ($this->downloaded($name)) { 487 | throw new Exceptions\HookAlreadyExistsException("Hook [{$name}] already exists."); 488 | } 489 | 490 | event(new Events\MakingHook($name)); 491 | 492 | // Ensure hooks folder exists 493 | if (!$this->filesystem->isDirectory(base_path('hooks'))) { 494 | $this->filesystem->makeDirectory(base_path('hooks')); 495 | } 496 | 497 | // Create folder for the new hook 498 | $this->filesystem->deleteDirectory(base_path("hooks/{$name}")); 499 | $this->filesystem->makeDirectory(base_path("hooks/{$name}")); 500 | 501 | // make stub files 502 | $this->makeStubFiles($name); 503 | 504 | event(new Events\MadeHook($name)); 505 | } 506 | 507 | protected function makeStubFiles($name) 508 | { 509 | $replaces = [ 510 | 'kebab-case' => $name, 511 | 'snake_case' => Str::snake(str_replace('-', '_', $name)), 512 | 'camelCase' => Str::camel(str_replace('-', '_', $name)), 513 | 'StudlyCase' => Str::studly(str_replace('-', '_', $name)), 514 | 'MIGRATION_DATE_TIME' => $this->migrationDateTimeString(), 515 | ]; 516 | 517 | $files = $this->filesystem->allFiles(__DIR__.'/../stub'); 518 | 519 | foreach ($files as $file) { 520 | if ($path = $file->getRelativePath()) { 521 | $parts = explode('/', str_replace('\\', '/', $path)); 522 | 523 | $location = base_path("hooks/{$name}"); 524 | 525 | foreach ($parts as $part) { 526 | $location .= "/{$part}"; 527 | 528 | if (!$this->filesystem->isDirectory($location)) { 529 | $this->filesystem->makeDirectory($location); 530 | } 531 | } 532 | } 533 | 534 | $content = $this->replace($this->filesystem->get($file->getRealPath()), $replaces); 535 | $filename = $this->replace($file->getRelativePathname(), $replaces); 536 | 537 | $this->filesystem->put(base_path("hooks/{$name}/{$filename}"), $content); 538 | } 539 | } 540 | 541 | protected function migrationDateTimeString() 542 | { 543 | $dateTime = Carbon::now(); 544 | 545 | if (static::$fakeDateTime) { 546 | $dateTime = static::$fakeDateTime; 547 | } 548 | 549 | return $dateTime->format('Y_m_d_His'); 550 | } 551 | 552 | protected function replace($content, array $replaces) 553 | { 554 | return str_replace(array_keys($replaces), array_values($replaces), $content); 555 | } 556 | 557 | /** 558 | * Check if hook is already installed. 559 | * 560 | * @param $name 561 | * 562 | * @return bool 563 | */ 564 | public function installed($name) 565 | { 566 | return isset($this->hooks[$name]); 567 | } 568 | 569 | /** 570 | * Check if hook is enabled. 571 | * 572 | * @param $name 573 | * 574 | * @return bool 575 | */ 576 | public function enabled($name) 577 | { 578 | return isset($this->hooks[$name]) && $this->hooks[$name]->enabled; 579 | } 580 | 581 | /** 582 | * Check if hook is disabled. 583 | * 584 | * @param $name 585 | * 586 | * @return bool 587 | */ 588 | public function disabled($name) 589 | { 590 | return !$this->enabled($name); 591 | } 592 | 593 | /** 594 | * Check if hook is located locally. 595 | * 596 | * @param $name 597 | * 598 | * @return bool 599 | */ 600 | public function local($name) 601 | { 602 | return $this->filesystem->isDirectory(base_path("hooks/{$name}")); 603 | } 604 | 605 | /** 606 | * Check if hook is downloaded. 607 | * 608 | * @param $name 609 | * 610 | * @return bool 611 | */ 612 | public function downloaded($name) 613 | { 614 | if ($this->local($name)) { 615 | return $this->filesystem->isDirectory(base_path("hooks/{$name}")) 616 | && $this->filesystem->exists(base_path("hooks/{$name}/composer.json")); 617 | } 618 | 619 | return $this->filesystem->isDirectory(base_path("vendor/{$name}")); 620 | } 621 | 622 | /** 623 | * Get the latest version number of a hook if outdated. 624 | * 625 | * @param $name 626 | * 627 | * @return string|null 628 | */ 629 | public function outdated($name) 630 | { 631 | if (isset($this->outdated[$name])) { 632 | return $this->outdated[$name]; 633 | } 634 | } 635 | 636 | /** 637 | * Get hook information. 638 | * 639 | * @param $name 640 | * 641 | * @throws \Larapack\Hooks\Exceptions\HookNotFoundException 642 | * @throws \Larapack\Hooks\Exceptions\HookNotInstalledException 643 | * 644 | * @return \Larapack\Hooks\Hook 645 | */ 646 | public function hook($name) 647 | { 648 | if (!$this->downloaded($name)) { 649 | throw new Exceptions\HookNotFoundException("Hook [{$name}] not found."); 650 | } 651 | 652 | if (!$this->installed($name)) { 653 | throw new Exceptions\HookNotInstalledException("Hook [{$name}] not installed."); 654 | } 655 | 656 | return $this->hooks[$name]; 657 | } 658 | 659 | /** 660 | * Get all hooks. 661 | * 662 | * @return \Illuminate\Support\Collection 663 | */ 664 | public function hooks() 665 | { 666 | return $this->hooks; 667 | } 668 | 669 | /** 670 | * Get type of hook. 671 | * 672 | * @param $name 673 | * 674 | * @return string 675 | */ 676 | public function type($name) 677 | { 678 | $hook = $this->hooks()->where('name', $name)->first(); 679 | 680 | if (!is_null($hook)) { 681 | return $hook->type; 682 | } 683 | } 684 | 685 | /** 686 | * Get version of hook. 687 | * 688 | * @param $name 689 | * 690 | * @return string|null 691 | */ 692 | public function version($name) 693 | { 694 | $data = $this->hook($name); 695 | 696 | return $data['version']; 697 | } 698 | 699 | /** 700 | * Get hook details from remote. 701 | * 702 | * @param $name 703 | * 704 | * @return array 705 | */ 706 | public function getRemoteDetails($name) 707 | { 708 | // Get remote 709 | $remote = json_decode(file_get_contents($this->getRemote()."/api/hooks/{$name}.json"), true); 710 | 711 | if ($remote['exists'] !== true) { 712 | throw new \InvalidArgumentException("Hook [{$name}] does not exists."); 713 | } 714 | 715 | return $remote; 716 | } 717 | 718 | /** 719 | * Make default hook data. 720 | * 721 | * @param $name 722 | * @param $type 723 | * @param bool $enable 724 | * 725 | * @return array 726 | */ 727 | public function makeDefaultHookData($name, $type, $enable = false) 728 | { 729 | return [ 730 | 'name' => $name, 731 | 'type' => $type, 732 | 'version' => null, 733 | 'enabled' => $enable, 734 | ]; 735 | } 736 | 737 | /** 738 | * Read hooks.json file. 739 | */ 740 | public function readJsonFile($localsIncluded = []) 741 | { 742 | $hooks = []; 743 | 744 | if (!$this->filesystem->exists(base_path('hooks'))) { 745 | $this->filesystem->makeDirectory(base_path('hooks')); 746 | } 747 | 748 | if (!$this->filesystem->exists(base_path('hooks/hooks.json'))) { 749 | $this->filesystem->put(base_path('hooks/hooks.json'), '{}'); 750 | } 751 | 752 | $data = json_decode($this->filesystem->get(base_path('hooks/hooks.json')), true); 753 | $enabled = []; 754 | 755 | if (isset($data['hooks'])) { 756 | foreach ($data['hooks'] as $key => $hook) { 757 | if (!$this->filesystem->exists(base_path("hooks/{$key}/composer.json")) && 758 | !$this->filesystem->exists(base_path("vendor/{$key}/composer.json"))) { 759 | continue; // This hook does not seem to exist anymore 760 | } 761 | 762 | $hooks[$key] = new Hook($hook); 763 | if ($hooks[$key]->enabled) { 764 | $enabled[] = $key; 765 | } 766 | } 767 | } 768 | 769 | if (isset($data['last_remote_check'])) { 770 | $this->lastRemoteCheck = Carbon::createFromTimestamp($data['last_remote_check']); 771 | } 772 | 773 | foreach ($this->readComposerHooks() as $name => $composerHook) { 774 | $hooks[$name] = $composerHook; 775 | 776 | if (in_array($name, $enabled)) { 777 | $hooks[$name]->enabled = true; 778 | } 779 | } 780 | 781 | foreach ($this->readLocalHooks() as $name => $composerHook) { 782 | if (!isset($hooks[$name]) && !in_array($name, $localsIncluded)) { 783 | continue; // Do not show not-installed local hooks. 784 | } 785 | 786 | $hooks[$name] = $composerHook; 787 | 788 | if (in_array($name, $enabled)) { 789 | $hooks[$name]->enabled = true; 790 | } 791 | } 792 | 793 | $this->hooks = collect($hooks); 794 | } 795 | 796 | public function readComposerHooks($file = null) 797 | { 798 | if (is_null($file)) { 799 | $file = base_path('composer.lock'); 800 | } 801 | 802 | $hooks = []; 803 | $composer = []; 804 | if ($this->filesystem->exists($file)) { 805 | $composer = json_decode($this->filesystem->get($file), true); 806 | } 807 | 808 | foreach (Arr::get($composer, 'packages', []) as $package) { 809 | if (Arr::get($package, 'notification-url') == static::$remote.'/downloads') { 810 | $hooks[$package['name']] = new Hook($package); 811 | } 812 | } 813 | 814 | return $hooks; 815 | } 816 | 817 | public function readLocalHooks() 818 | { 819 | $hooks = []; 820 | $directories = Arr::except($this->filesystem->directories(base_path('hooks')), ['.', '..']); 821 | foreach ($directories as $directory) { 822 | if (!$this->filesystem->exists($directory.'/composer.json')) { 823 | continue; 824 | } 825 | 826 | $composer = json_decode($this->filesystem->get($directory.'/composer.json'), true); 827 | 828 | if (!is_null($composer) && isset($composer['name'])) { 829 | $composer['type'] = 'local'; 830 | $hooks[$composer['name']] = new Hook($composer); 831 | } 832 | } 833 | 834 | return $hooks; 835 | } 836 | 837 | /** 838 | * Remake hooks.json file. 839 | */ 840 | public function remakeJson() 841 | { 842 | $json = json_encode([ 843 | 'last_remote_check' => (!is_null($this->lastRemoteCheck) ? $this->lastRemoteCheck->timestamp : null), 844 | 'hooks' => $this->hooks(), 845 | ], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); 846 | 847 | file_put_contents(base_path('hooks/hooks.json'), $json); 848 | } 849 | 850 | public function composerRequire(array $packages) 851 | { 852 | return $this->runComposer([ 853 | 'command' => 'require', 854 | 'packages' => $packages, 855 | ]); 856 | } 857 | 858 | public function runComposer($input) 859 | { 860 | $input = new ArrayInput(array_merge([ 861 | '--working-dir' => base_path('/'), 862 | ], $input)); 863 | 864 | $this->composer->run($input, $output = new RawOutput()); 865 | 866 | $this->composerOutput[] = $output; 867 | 868 | Application::setInstance($this->app); 869 | 870 | return $output->output(); 871 | } 872 | 873 | public function checkForUpdates() 874 | { 875 | $output = $this->runComposer([ 876 | 'command' => 'outdated', 877 | '--format' => 'json', 878 | ]); 879 | 880 | $outdated = []; 881 | $hooks = []; 882 | $results = json_decode($output, true); 883 | 884 | foreach (Arr::get($results, 'installed', []) as $package) { 885 | if (isset($this->hooks[Arr::get($package, 'name')])) { 886 | $outdated[$package['name']] = $package['latest']; 887 | $hook = $this->hooks[$package['name']]; 888 | $hook->setLatest($package['latest']); 889 | $hooks[] = $hook; 890 | } 891 | } 892 | 893 | $this->filesystem->put( 894 | base_path('hooks/outdated.json'), 895 | json_encode($output, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) 896 | ); 897 | 898 | $this->lastRemoteCheck = Carbon::now(); 899 | 900 | $this->remakeJson(); 901 | 902 | return collect($hooks); 903 | } 904 | 905 | /** 906 | * Run migrations found for a specific hook. 907 | * 908 | * @param \Larapack\Hooks\Hook $hook 909 | */ 910 | protected function migrateHook(Hook $hook) 911 | { 912 | $migrations = (array) $hook->getComposerHookKey('migrations', []); 913 | 914 | foreach ($migrations as $path) { 915 | if ($this->filesystem->isDirectory($hook->getPath().'/'.$path)) { 916 | $this->migrator->run($this->realPath([$path], $hook->getPath().'/')->all()); 917 | } else { 918 | $this->migrator->runFiles($this->realPath([$path], $hook->getPath().'/')->all()); 919 | } 920 | } 921 | } 922 | 923 | /** 924 | * Rollback migrations found for a specific hook. 925 | * 926 | * @param \Larapack\Hooks\Hook $hook 927 | */ 928 | protected function unmigrateHook(Hook $hook) 929 | { 930 | $migrations = (array) $hook->getComposerHookKey('migrations', []); 931 | 932 | foreach ($migrations as $path) { 933 | if ($this->filesystem->isDirectory($hook->getPath().'/'.$path)) { 934 | $this->migrator->reset($this->realPath([$path], $hook->getPath().'/')->all()); 935 | } else { 936 | $this->migrator->resetFiles($this->realPath([$path], $hook->getPath().'/')->all()); 937 | } 938 | } 939 | } 940 | 941 | /** 942 | * Run seeders found for a specific hook. 943 | * 944 | * @param \Larapack\Hooks\Hook $hook 945 | */ 946 | protected function seedHook(Hook $hook) 947 | { 948 | $folders = (array) $hook->getComposerHookKey('seeders', []); 949 | $basePath = $hook->getPath().'/'; 950 | 951 | $this->runSeeders($folders, $basePath); 952 | } 953 | 954 | /** 955 | * Run unseeders found for a specific hook. 956 | * 957 | * @param \Larapack\Hooks\Hook $hook 958 | */ 959 | protected function unseedHook(Hook $hook) 960 | { 961 | $folders = (array) $hook->getComposerHookKey('unseeders', []); 962 | $basePath = $hook->getPath().'/'; 963 | 964 | $this->runSeeders($folders, $basePath); 965 | } 966 | 967 | /** 968 | * Publish assets found for a specific hook. 969 | * 970 | * @param \Larapack\Hooks\Hook $hook 971 | */ 972 | protected function publishHook(Hook $hook, $force = false) 973 | { 974 | $folders = (array) $hook->getComposerHookKey('assets', []); 975 | $basePath = $hook->getPath().'/'; 976 | 977 | $filesystem = $this->filesystem; 978 | foreach ($folders as $location => $publish) { 979 | $publishPath = base_path($publish); 980 | if (!$realLocation = realpath($basePath.$location)) { 981 | continue; 982 | } 983 | 984 | if ($filesystem->isDirectory($realLocation)) { 985 | $allFiles = collect($filesystem->allFiles($realLocation))->map(function ($file) use ($realLocation) { 986 | return substr($file->getRealPath(), strlen($realLocation) + 1); 987 | }); 988 | } else { 989 | $allFiles = collect([new \Symfony\Component\Finder\SplFileInfo( 990 | $realLocation, 991 | '', 992 | basename($realLocation) 993 | )]); 994 | } 995 | 996 | $newFiles = $allFiles->filter(function ($filename) use ($publishPath, $filesystem) { 997 | return !$filesystem->exists($publishPath.'/'.$filename); 998 | }); 999 | 1000 | $updatedFiles = $allFiles->filter(function ($filename) use ($publishPath, $filesystem) { 1001 | return $filesystem->exists($publishPath.'/'.$filename); 1002 | }); 1003 | 1004 | if (!$force && isset($this->tempDirectories[$hook->name])) { 1005 | $tempLocation = $this->tempDirectories[$hook->name].'/'.$location; 1006 | $updatedFiles = $updatedFiles 1007 | ->filter(function ($filename) use ($tempLocation, $publishPath, $filesystem) { 1008 | if (!$filesystem->exists($tempLocation.'/'.$filename)) { 1009 | return true; 1010 | } 1011 | 1012 | return md5_file($tempLocation.'/'.$filename) == 1013 | md5_file($publishPath.'/'.$filename); 1014 | }); 1015 | } 1016 | 1017 | $newFiles->merge($updatedFiles) 1018 | ->each(function ($filename) use ($realLocation, $publishPath, $filesystem) { 1019 | if (!$filesystem->isDirectory($realLocation)) { 1020 | $directory = substr($publishPath, 0, -strlen(basename($publishPath))); 1021 | 1022 | if (!$filesystem->isDirectory($directory)) { 1023 | $filesystem->makeDirectory($directory, 0755, true, true); 1024 | } 1025 | 1026 | return $filesystem->copy($realLocation, $publishPath); 1027 | } 1028 | 1029 | $directory = substr($publishPath.'/'.$filename, 0, -strlen(basename($filename))); 1030 | 1031 | if (!$filesystem->isDirectory($directory)) { 1032 | $filesystem->makeDirectory($directory, 0755, true, true); 1033 | } 1034 | 1035 | $filesystem->delete($publishPath.'/'.$filename); 1036 | $filesystem->copy( 1037 | $realLocation.'/'.$filename, 1038 | $publishPath.'/'.$filename 1039 | ); 1040 | }); 1041 | } 1042 | } 1043 | 1044 | /** 1045 | * Unpublish assets found for a specific hook. 1046 | * 1047 | * @param \Larapack\Hooks\Hook $hook 1048 | */ 1049 | protected function unpublishHook(Hook $hook) 1050 | { 1051 | $folders = (array) $hook->getComposerHookKey('assets', []); 1052 | $basePath = $hook->getPath().'/'; 1053 | 1054 | $filesystem = $this->filesystem; 1055 | foreach ($folders as $location => $publish) { 1056 | $publishPath = base_path($publish); 1057 | if (!$realLocation = realpath($basePath.$location)) { 1058 | continue; 1059 | } 1060 | 1061 | if ($filesystem->isDirectory($realLocation)) { 1062 | $allFiles = collect($this->filesystem->allFiles($realLocation)) 1063 | ->map(function ($file) use ($realLocation) { 1064 | return substr($file->getRealPath(), strlen($realLocation) + 1); 1065 | }); 1066 | } else { 1067 | $allFiles = collect([new \Symfony\Component\Finder\SplFileInfo( 1068 | $realLocation, 1069 | '', 1070 | basename($realLocation) 1071 | )]); 1072 | } 1073 | 1074 | $existingFiles = $allFiles->filter(function ($filename) use ($publishPath, $filesystem) { 1075 | if ($filesystem->isDirectory($publishPath)) { 1076 | return $filesystem->exists($publishPath.'/'.$filename); 1077 | } 1078 | 1079 | return $filesystem->exists($publishPath); 1080 | }); 1081 | 1082 | $existingFiles->each(function ($filename) use ($publishPath, $filesystem) { 1083 | if ($filesystem->isDirectory($publishPath)) { 1084 | return $filesystem->delete($publishPath.'/'.$filename); 1085 | } 1086 | 1087 | $filesystem->delete($publishPath); 1088 | }); 1089 | } 1090 | } 1091 | 1092 | /** 1093 | * Run seeder files. 1094 | * 1095 | * @param array $folders 1096 | * @param string $basePath 1097 | */ 1098 | protected function runSeeders($folders, $basePath) 1099 | { 1100 | $filesystem = $this->filesystem; 1101 | 1102 | $this->realPath($folders, $basePath) 1103 | ->each(function ($folder) use ($filesystem) { 1104 | if ($filesystem->isDirectory($folder)) { 1105 | $files = $filesystem->files($folder); 1106 | } else { 1107 | $files = [new \Symfony\Component\Finder\SplFileInfo( 1108 | $folder, 1109 | '', 1110 | basename($folder) 1111 | )]; 1112 | } 1113 | 1114 | collect($files)->filter(function ($file) { 1115 | return $file->getExtension() == 'php'; 1116 | })->each(function ($file) { 1117 | $class = substr($file->getFilename(), 0, -4); 1118 | require_once $file->getRealPath(); 1119 | 1120 | (new $class())->run(); 1121 | }); 1122 | }); 1123 | } 1124 | 1125 | /** 1126 | * Get collection of realpath paths. 1127 | * 1128 | * @param array $paths 1129 | * @param string $basePath 1130 | * 1131 | * @return \Illuminate\Support\Collection 1132 | */ 1133 | protected function realPath(array $paths, $basePath = '') 1134 | { 1135 | return collect($paths)->map(function ($path) use ($basePath) { 1136 | return realpath($basePath.$path); 1137 | })->filter(function ($path) { 1138 | return $path; 1139 | }); 1140 | } 1141 | 1142 | /** 1143 | * Make temponary backup of hook. 1144 | * 1145 | * @param \Larapack\Hooks\Hook $hook 1146 | * 1147 | * @return void 1148 | */ 1149 | protected function makeTemponaryBackup(Hook $hook) 1150 | { 1151 | $folder = $this->createTempFolder(); 1152 | $this->filesystem->copyDirectory($hook->getPath(), $folder); 1153 | 1154 | $this->tempDirectories[$hook->name] = $folder; 1155 | } 1156 | 1157 | protected function createTempFolder() 1158 | { 1159 | $path = sys_get_temp_dir().'/hooks-'.uniqid(); 1160 | 1161 | if ($this->filesystem->exists($path)) { 1162 | return $this->createTempFolder(); 1163 | } 1164 | 1165 | return $path; 1166 | } 1167 | 1168 | protected function clearTemponaryFiles() 1169 | { 1170 | foreach ($this->tempDirectories as $directory) { 1171 | $this->filesystem->deleteDirectory($directory); 1172 | } 1173 | } 1174 | } 1175 | 1176 | // TODO: MOVE! 1177 | class RawOutput extends \Symfony\Component\Console\Output\Output 1178 | { 1179 | protected $content; 1180 | 1181 | public function doWrite($message, $newline) 1182 | { 1183 | $this->content .= $message; 1184 | 1185 | if ($newline) { 1186 | $this->content .= "\n"; 1187 | } 1188 | } 1189 | 1190 | public function output() 1191 | { 1192 | return $this->content; 1193 | } 1194 | } 1195 | -------------------------------------------------------------------------------- /src/HooksFacade.php: -------------------------------------------------------------------------------- 1 | mergeConfigFrom($configPath, 'hooks'); 19 | 20 | if (!config('hooks.enabled', true)) { 21 | return; 22 | } 23 | 24 | $this->registerCommands(); 25 | 26 | $this->publishes( 27 | [$configPath => config_path('hooks.php')], 28 | 'hooks-config' 29 | ); 30 | 31 | // Register Hooks system and aliases 32 | $this->app->singleton(Hooks::class, function ($app) { 33 | $filesystem = $app[Filesystem::class]; 34 | $migrator = $app[Migrator::class]; 35 | 36 | return new Hooks($filesystem, $migrator); 37 | }); 38 | 39 | $this->app->alias(Hooks::class, 'hooks'); 40 | 41 | // The migrator is responsible for actually running and rollback the migration 42 | // files in the application. We'll pass in our database connection resolver 43 | // so the migrator can resolve any of these connections when it needs to. 44 | $this->app->singleton(Migrator::class, function ($app) { 45 | $repository = $app['migration.repository']; 46 | 47 | return new Migrator($repository, $app['db'], $app['files']); 48 | }); 49 | } 50 | 51 | /** 52 | * Register Hook Service Providers. 53 | */ 54 | public function registerHookProviders() 55 | { 56 | // load only the enabled hooks 57 | $hooks = $this->app['hooks']->hooks()->where('enabled', true); 58 | $loader = AliasLoader::getInstance(); 59 | 60 | foreach ($hooks as $hook) { 61 | // load providers 62 | foreach ($hook->getProviders() as $provider) { 63 | $this->app->register($provider); 64 | } 65 | 66 | // set aliases 67 | foreach ($hook->getAliases() as $alias => $class) { 68 | $loader->alias($alias, $class); 69 | } 70 | } 71 | } 72 | 73 | /** 74 | * Bootstrap the application services. 75 | */ 76 | public function boot() 77 | { 78 | if (!config('hooks.enabled', true)) { 79 | return; 80 | } 81 | 82 | // Register hook providers 83 | $this->registerHookProviders(); 84 | } 85 | 86 | /** 87 | * Register commands. 88 | */ 89 | protected function registerCommands() 90 | { 91 | $this->commands(Commands\SetupCommand::class); 92 | $this->commands(Commands\MakeCommand::class); 93 | $this->commands(Commands\InstallCommand::class); 94 | $this->commands(Commands\UninstallCommand::class); 95 | $this->commands(Commands\UpdateCommand::class); 96 | $this->commands(Commands\CheckCommand::class); 97 | $this->commands(Commands\EnableCommand::class); 98 | $this->commands(Commands\DisableCommand::class); 99 | $this->commands(Commands\InfoCommand::class); 100 | $this->commands(Commands\ListCommand::class); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/Migrator.php: -------------------------------------------------------------------------------- 1 | notes = []; 20 | 21 | $this->requireFiles($migrations = $this->pendingMigrations( 22 | $files, 23 | $this->repository->getRan() 24 | )); 25 | 26 | // Once we have all these migrations that are outstanding we are ready to run 27 | // we will go ahead and run them "up". This will execute each migration as 28 | // an operation against a database. Then we'll return this list of them. 29 | $this->runPending($migrations, $options); 30 | 31 | return $migrations; 32 | } 33 | 34 | public function resetFiles(array $files = [], $pretend = false) 35 | { 36 | $this->notes = []; 37 | 38 | $files = collect($files)->keyBy(function ($file) { 39 | return rtrim(basename($file), '.php'); 40 | })->all(); 41 | 42 | // Next, we will reverse the migration list so we can run them back in the 43 | // correct order for resetting this database. This will allow us to get 44 | // the database back into its "empty" state ready for the migrations. 45 | $migrations = array_reverse($this->repository->getRan()); 46 | 47 | if (count($migrations) === 0) { 48 | $this->note('Nothing to rollback.'); 49 | 50 | return []; 51 | } 52 | 53 | return $this->resetMigrationsByFiles($migrations, $files, $pretend); 54 | } 55 | 56 | protected function resetMigrationsByFiles(array $migrations, array $files, $pretend = false) 57 | { 58 | // Since the getRan method that retrieves the migration name just gives us the 59 | // migration name, we will format the names into objects with the name as a 60 | // property on the objects so that we can pass it to the rollback method. 61 | $migrations = collect($migrations)->map(function ($m) { 62 | return (object) ['migration' => $m]; 63 | })->all(); 64 | 65 | return $this->rollbackMigrationsByFiles( 66 | $migrations, 67 | $files, 68 | compact('pretend') 69 | ); 70 | } 71 | 72 | protected function rollbackMigrationsByFiles(array $migrations, $files, array $options) 73 | { 74 | $rolledBack = []; 75 | 76 | $this->requireFiles($files); 77 | 78 | // Next we will run through all of the migrations and call the "down" method 79 | // which will reverse each migration in order. This getLast method on the 80 | // repository already returns these migration's names in reverse order. 81 | foreach ($migrations as $migration) { 82 | $migration = (object) $migration; 83 | 84 | if (!$file = Arr::get($files, $migration->migration)) { 85 | $this->note("Migration not found: {$migration->migration}"); 86 | 87 | continue; 88 | } 89 | 90 | $rolledBack[] = $file; 91 | 92 | $this->runDown( 93 | $file, 94 | $migration, 95 | Arr::get($options, 'pretend', false) 96 | ); 97 | } 98 | 99 | return $rolledBack; 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /stub/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "kebab-case", 3 | "description": "This is my first hook.", 4 | "require": { 5 | "larapack/hooks": "^1.0.5" 6 | }, 7 | "autoload": { 8 | "psr-4": { 9 | "StudlyCase\\": "src/" 10 | } 11 | }, 12 | "extra": { 13 | "hook": { 14 | "providers": [ 15 | "StudlyCase\\StudlyCaseServiceProvider" 16 | ], 17 | "aliases": { 18 | "StudlyCase": "StudlyCase\\StudlyCaseFacade" 19 | }, 20 | "migrations": [ 21 | "resources/database/migrations" 22 | ], 23 | "seeders": [ 24 | "resources/database/seeders" 25 | ], 26 | "unseeders": [ 27 | "resources/database/unseeders" 28 | ], 29 | "assets": { 30 | "resources/assets": "public/vendor/kebab-case" 31 | } 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /stub/resources/assets/scripts/alert.js: -------------------------------------------------------------------------------- 1 | alert('This is a sample file!'); 2 | -------------------------------------------------------------------------------- /stub/resources/database/migrations/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/larapack/hooks/ce2c8c078a56036c357f26036174412cb9059f8e/stub/resources/database/migrations/.gitkeep -------------------------------------------------------------------------------- /stub/resources/database/migrations/MIGRATION_DATE_TIME_create_snake_case_table.php: -------------------------------------------------------------------------------- 1 | increments('id'); 18 | 19 | $table->string('name'); 20 | 21 | $table->timestamps(); 22 | }); 23 | } 24 | 25 | /** 26 | * Reverse the migrations. 27 | * 28 | * @return void 29 | */ 30 | public function down() 31 | { 32 | Schema::dropIfExists('snake_case'); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /stub/resources/database/seeders/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/larapack/hooks/ce2c8c078a56036c357f26036174412cb9059f8e/stub/resources/database/seeders/.gitkeep -------------------------------------------------------------------------------- /stub/resources/database/seeders/StudlyCaseTableSeeder.php: -------------------------------------------------------------------------------- 1 | count() > 0) { 17 | return; 18 | } 19 | 20 | DB::table('snake_case')->insert([ 21 | ['name' => 'foo'], 22 | ['name' => 'bar'], 23 | ['name' => 'baz'], 24 | ]); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /stub/resources/database/unseeders/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/larapack/hooks/ce2c8c078a56036c357f26036174412cb9059f8e/stub/resources/database/unseeders/.gitkeep -------------------------------------------------------------------------------- /stub/resources/database/unseeders/StudlyCaseTableUnseeder.php: -------------------------------------------------------------------------------- 1 | whereIn('name', ['foo', 'bar', 'baz']) 23 | ->delete(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /stub/src/StudlyCase.php: -------------------------------------------------------------------------------- 1 | assertTrue($composer->has('repositories')); 33 | $this->assertEquals([ 34 | 'hooks' => [ 35 | 'url' => static::COMPOSER_REPOSITORY, 36 | 'type' => 'composer', 37 | ], 38 | ], $composer->get('repositories')); 39 | } 40 | 41 | public function test_install_hook_from_github() 42 | { 43 | $filesystem = app(Filesystem::class); 44 | 45 | // Install hook 46 | $this->artisan('hook:install', [ 47 | 'name' => 'composer-github-hook', 48 | ]); 49 | 50 | // Check that hooks folder does exists 51 | $this->assertDirectoryExists(base_path('hooks')); 52 | 53 | // Check that the hook folder exists 54 | $this->assertDirectoryExists(base_path('vendor/composer-github-hook')); 55 | 56 | // Check that the hook details is correct 57 | $hook = app('hooks')->hook('composer-github-hook'); 58 | $expect = [ 59 | 'name' => 'composer-github-hook', 60 | 'version' => 'v1.0.1', 61 | 'description' => 'This is a hook', 62 | 'enabled' => false, 63 | ]; 64 | foreach ($expect as $key => $value) { 65 | $this->assertEquals($value, $hook->$key); 66 | } 67 | 68 | $this->assertFalse($hook->isLocal()); 69 | } 70 | 71 | public function test_install_hook_from_github_with_enable_option() 72 | { 73 | // Install hook and enable hook 74 | $this->artisan('hook:install', [ 75 | 'name' => 'composer-github-hook', 76 | '--enable' => true, 77 | ]); 78 | 79 | // Check that hook is enabled 80 | $hook = app('hooks')->hook('composer-github-hook'); 81 | $this->assertTrue($hook->enabled); 82 | } 83 | 84 | public function test_making_local_hook() 85 | { 86 | $filesystem = app(Filesystem::class); 87 | Hooks::fakeDateTime($carbon = Carbon::createFromFormat('Y/m/d H:i:s', '2018/01/20 12:00:00')); 88 | 89 | $migrationDateTime = $carbon->format('Y_m_d_His'); 90 | 91 | // Make hook 92 | $this->artisan('hook:make', [ 93 | 'name' => 'local-test-hook', 94 | ]); 95 | 96 | // Check that hooks folder does exists 97 | $this->assertDirectoryExists(base_path('hooks')); 98 | 99 | // Check that the hook folder exists 100 | $this->assertDirectoryExists(base_path('hooks/local-test-hook')); 101 | 102 | // Check that hook is not yet installed 103 | $this->assertCount(0, app('hooks')->hooks()->all()); 104 | 105 | // Check stubs 106 | $this->assertFileExists(base_path('hooks/local-test-hook/composer.json')); 107 | $this->assertEquals( 108 | $filesystem->get(__DIR__.'/fixtures/composer.json'), 109 | $filesystem->get(base_path('hooks/local-test-hook/composer.json')) 110 | ); 111 | 112 | $this->assertFileExists(base_path('hooks/local-test-hook/src/LocalTestHook.php')); 113 | $this->assertEquals( 114 | $filesystem->get(__DIR__.'/fixtures/src/LocalTestHook.php'), 115 | $filesystem->get(base_path('hooks/local-test-hook/src/LocalTestHook.php')) 116 | ); 117 | 118 | $this->assertFileExists(base_path('hooks/local-test-hook/src/LocalTestHookFacade.php')); 119 | $this->assertEquals( 120 | $filesystem->get(__DIR__.'/fixtures/src/LocalTestHookFacade.php'), 121 | $filesystem->get(base_path('hooks/local-test-hook/src/LocalTestHookFacade.php')) 122 | ); 123 | 124 | $this->assertFileExists(base_path('hooks/local-test-hook/src/LocalTestHookServiceProvider.php')); 125 | $this->assertEquals( 126 | $filesystem->get(__DIR__.'/fixtures/src/LocalTestHookServiceProvider.php'), 127 | $filesystem->get(base_path('hooks/local-test-hook/src/LocalTestHookServiceProvider.php')) 128 | ); 129 | 130 | $this->assertFileExists(base_path('hooks/local-test-hook/resources/assets/scripts/alert.js')); 131 | $this->assertEquals( 132 | $filesystem->get(__DIR__.'/fixtures/resources/assets/scripts/alert.js'), 133 | $filesystem->get(base_path('hooks/local-test-hook/resources/assets/scripts/alert.js')) 134 | ); 135 | 136 | $this->assertFileExists(base_path( 137 | 'hooks/local-test-hook/resources/database/migrations/'.$migrationDateTime.'_create_local_test_hook_table.php' 138 | )); 139 | $this->assertEquals( 140 | $filesystem->get(__DIR__.'/fixtures/resources/database/migrations/'.$migrationDateTime.'_create_local_test_hook_table.php'), 141 | $filesystem->get(base_path('hooks/local-test-hook/resources/database/migrations/'.$migrationDateTime.'_create_local_test_hook_table.php')) 142 | ); 143 | 144 | $this->assertFileExists(base_path( 145 | 'hooks/local-test-hook/resources/database/seeders/LocalTestHookTableSeeder.php' 146 | )); 147 | $this->assertEquals( 148 | $filesystem->get(__DIR__.'/fixtures/resources/database/seeders/LocalTestHookTableSeeder.php'), 149 | $filesystem->get(base_path('hooks/local-test-hook/resources/database/seeders/LocalTestHookTableSeeder.php')) 150 | ); 151 | 152 | $this->assertFileExists(base_path( 153 | 'hooks/local-test-hook/resources/database/unseeders/LocalTestHookTableUnseeder.php' 154 | )); 155 | $this->assertEquals( 156 | $filesystem->get(__DIR__.'/fixtures/resources/database/unseeders/LocalTestHookTableUnseeder.php'), 157 | $filesystem->get(base_path('hooks/local-test-hook/resources/database/unseeders/LocalTestHookTableUnseeder.php')) 158 | ); 159 | } 160 | 161 | public function test_installing_local_hook() 162 | { 163 | // Make hook 164 | $this->artisan('hook:make', [ 165 | 'name' => 'local-test-hook', 166 | ]); 167 | 168 | // Install hook 169 | $this->artisan('hook:install', [ 170 | 'name' => 'local-test-hook', 171 | ]); 172 | 173 | // Check that the hook details is correct 174 | $hook = app('hooks')->hook('local-test-hook'); 175 | $expect = [ 176 | 'name' => 'local-test-hook', 177 | 'version' => null, 178 | 'description' => 'This is my first hook.', 179 | 'enabled' => false, 180 | ]; 181 | foreach ($expect as $key => $value) { 182 | $this->assertEquals($value, $hook->$key); 183 | } 184 | 185 | $this->assertTrue($hook->isLocal()); 186 | } 187 | 188 | public function test_enabling_hook() 189 | { 190 | $filesystem = app(Filesystem::class); 191 | 192 | // Make hook 193 | $this->artisan('hook:make', [ 194 | 'name' => 'local-test-hook', 195 | ]); 196 | 197 | // Check that hooks folder does exists 198 | $this->assertDirectoryExists(base_path('hooks')); 199 | 200 | // Check that the hook folder exists 201 | $this->assertDirectoryExists(base_path('hooks/local-test-hook')); 202 | 203 | // Check that hook is not yet installed 204 | $hooks = app('hooks')->hooks()->all(); 205 | $this->assertCount(0, $hooks); 206 | 207 | // Install hook 208 | $this->artisan('hook:install', [ 209 | 'name' => 'local-test-hook', 210 | ]); 211 | 212 | // Check that the hook details is correct 213 | $hook = app('hooks')->hook('local-test-hook'); 214 | $expect = [ 215 | 'name' => 'local-test-hook', 216 | 'version' => null, 217 | 'description' => 'This is my first hook.', 218 | 'enabled' => false, 219 | ]; 220 | foreach ($expect as $key => $value) { 221 | $this->assertEquals($value, $hook->$key); 222 | } 223 | 224 | $this->assertTrue($hook->isLocal()); 225 | 226 | // Enable hook 227 | $this->artisan('hook:enable', [ 228 | 'name' => 'local-test-hook', 229 | ]); 230 | 231 | // Check that the hook details is correct 232 | $hook = app('hooks')->hook('local-test-hook'); 233 | $expect = [ 234 | 'name' => 'local-test-hook', 235 | 'version' => null, 236 | 'description' => 'This is my first hook.', 237 | 'enabled' => true, 238 | ]; 239 | foreach ($expect as $key => $value) { 240 | $this->assertEquals($value, $hook->$key); 241 | } 242 | 243 | $this->assertTrue($hook->isLocal()); 244 | } 245 | 246 | public function test_disabling_hook() 247 | { 248 | $filesystem = app(Filesystem::class); 249 | 250 | // Make hook 251 | $this->artisan('hook:make', [ 252 | 'name' => 'local-test-hook', 253 | ]); 254 | 255 | // Check that hooks folder does exists 256 | $this->assertDirectoryExists(base_path('hooks')); 257 | 258 | // Check that the hook folder exists 259 | $this->assertDirectoryExists(base_path('hooks/local-test-hook')); 260 | 261 | // Check that hook is not yet installed 262 | $hooks = app('hooks')->hooks()->all(); 263 | $this->assertCount(0, $hooks); 264 | 265 | // Install hook 266 | $this->artisan('hook:install', [ 267 | 'name' => 'local-test-hook', 268 | ]); 269 | 270 | // Check that the hook details is correct 271 | $hook = app('hooks')->hook('local-test-hook'); 272 | $expect = [ 273 | 'name' => 'local-test-hook', 274 | 'version' => null, 275 | 'description' => 'This is my first hook.', 276 | 'enabled' => false, 277 | ]; 278 | foreach ($expect as $key => $value) { 279 | $this->assertEquals($value, $hook->$key); 280 | } 281 | 282 | $this->assertTrue($hook->isLocal()); 283 | 284 | // Enable hook 285 | $this->artisan('hook:enable', [ 286 | 'name' => 'local-test-hook', 287 | ]); 288 | 289 | // Check that the hook details is correct 290 | $hook = app('hooks')->hook('local-test-hook'); 291 | $expect = [ 292 | 'name' => 'local-test-hook', 293 | 'version' => null, 294 | 'description' => 'This is my first hook.', 295 | 'enabled' => true, 296 | ]; 297 | foreach ($expect as $key => $value) { 298 | $this->assertEquals($value, $hook->$key); 299 | } 300 | 301 | $this->assertTrue($hook->isLocal()); 302 | 303 | // Disable hook 304 | $this->artisan('hook:disable', [ 305 | 'name' => 'local-test-hook', 306 | ]); 307 | 308 | // Check that the hook details is correct 309 | $hook = app('hooks')->hook('local-test-hook'); 310 | $expect = [ 311 | 'name' => 'local-test-hook', 312 | 'version' => null, 313 | 'description' => 'This is my first hook.', 314 | 'enabled' => false, 315 | ]; 316 | foreach ($expect as $key => $value) { 317 | $this->assertEquals($value, $hook->$key); 318 | } 319 | 320 | $this->assertTrue($hook->isLocal()); 321 | } 322 | 323 | public function test_uninstall_hook() 324 | { 325 | $filesystem = app(Filesystem::class); 326 | 327 | // Make hook 328 | $this->artisan('hook:make', [ 329 | 'name' => 'local-test-hook', 330 | ]); 331 | 332 | // Check that hooks folder does exists 333 | $this->assertDirectoryExists(base_path('hooks')); 334 | 335 | // Check that the hook folder exists 336 | $this->assertDirectoryExists(base_path('hooks/local-test-hook')); 337 | 338 | // Check that hook is not yet installed 339 | $hooks = app('hooks')->hooks()->all(); 340 | $this->assertCount(0, $hooks); 341 | 342 | // Install hook 343 | $this->artisan('hook:install', [ 344 | 'name' => 'local-test-hook', 345 | ]); 346 | 347 | // Check that the hook details is correct 348 | $hook = app('hooks')->hook('local-test-hook'); 349 | $expect = [ 350 | 'name' => 'local-test-hook', 351 | 'version' => null, 352 | 'description' => 'This is my first hook.', 353 | 'enabled' => false, 354 | ]; 355 | foreach ($expect as $key => $value) { 356 | $this->assertEquals($value, $hook->$key); 357 | } 358 | 359 | $this->assertTrue($hook->isLocal()); 360 | 361 | // Uninstall hook 362 | $this->artisan('hook:uninstall', [ 363 | 'name' => 'local-test-hook', 364 | '--delete' => true, 365 | ]); 366 | 367 | // Check that the hook folder exists 368 | $this->assertDirectoryNotExists(base_path('hooks/local-test-hook')); 369 | } 370 | 371 | public function test_uninstall_hook_without_delete_parameter() 372 | { 373 | $filesystem = app(Filesystem::class); 374 | 375 | // Make hook 376 | $this->artisan('hook:make', [ 377 | 'name' => 'local-test-hook', 378 | ]); 379 | 380 | // Check that hooks folder does exists 381 | $this->assertDirectoryExists(base_path('hooks')); 382 | 383 | // Check that the hook folder exists 384 | $this->assertDirectoryExists(base_path('hooks/local-test-hook')); 385 | 386 | // Check that hook is not yet installed 387 | $hooks = app('hooks')->hooks()->all(); 388 | $this->assertCount(0, $hooks); 389 | 390 | // Install hook 391 | $this->artisan('hook:install', [ 392 | 'name' => 'local-test-hook', 393 | ]); 394 | 395 | // Check that the hook details is correct 396 | $hook = app('hooks')->hook('local-test-hook'); 397 | $expect = [ 398 | 'name' => 'local-test-hook', 399 | 'version' => null, 400 | 'description' => 'This is my first hook.', 401 | 'enabled' => false, 402 | ]; 403 | foreach ($expect as $key => $value) { 404 | $this->assertEquals($value, $hook->$key); 405 | } 406 | 407 | $this->assertTrue($hook->isLocal()); 408 | 409 | // Uninstall hook 410 | $this->artisan('hook:uninstall', [ 411 | 'name' => 'local-test-hook', 412 | ]); 413 | 414 | // Check that the hook folder exists 415 | $this->assertDirectoryExists(base_path('hooks/local-test-hook')); 416 | } 417 | 418 | public function test_installing_specific_version() 419 | { 420 | $filesystem = app(Filesystem::class); 421 | 422 | // Install hook 423 | $this->artisan('hook:install', [ 424 | 'name' => 'composer-github-hook', 425 | 'version' => 'v1.0.0', 426 | ]); 427 | 428 | // Check that the hook folder exists 429 | $this->assertDirectoryExists(base_path('vendor/composer-github-hook')); 430 | 431 | // Check that the hook details is correct 432 | $hook = app('hooks')->hook('composer-github-hook'); 433 | $expect = [ 434 | 'name' => 'composer-github-hook', 435 | 'version' => 'v1.0.0', 436 | 'description' => 'This is a hook', 437 | 'enabled' => false, 438 | ]; 439 | foreach ($expect as $key => $value) { 440 | $this->assertEquals($value, $hook->$key); 441 | } 442 | 443 | $this->assertFalse($hook->isLocal()); 444 | 445 | // Check that version is correct 446 | $this->assertEquals('v1.0.0', trim($filesystem->get(base_path('vendor/composer-github-hook/version')))); 447 | } 448 | 449 | public function test_update_hook() 450 | { 451 | $filesystem = app(Filesystem::class); 452 | 453 | // Install hook 454 | $this->artisan('hook:install', [ 455 | 'name' => 'composer-github-hook', 456 | 'version' => 'v1.0.0', 457 | ]); 458 | 459 | Hooks::useVersionWildcardOnUpdate(); 460 | 461 | // Update hook 462 | $this->artisan('hook:update', [ 463 | 'name' => 'composer-github-hook', 464 | ]); 465 | 466 | // Check version is correct 467 | $hook = app('hooks')->hook('composer-github-hook'); 468 | $this->assertEquals('v1.0.1', $hook->version); 469 | } 470 | 471 | public function test_updating_to_specific_version() 472 | { 473 | // Install hook 474 | $this->artisan('hook:install', [ 475 | 'name' => 'composer-github-hook', 476 | 'version' => 'v1.0.0', 477 | ]); 478 | 479 | // Update hook 480 | $this->artisan('hook:update', [ 481 | 'name' => 'composer-github-hook', 482 | 'version' => 'v1.0.1', 483 | ]); 484 | 485 | // Check version is correct 486 | $hook = app('hooks')->hook('composer-github-hook'); 487 | $this->assertEquals('v1.0.1', $hook->version); 488 | } 489 | 490 | public function test_checking_hooks_for_updates() 491 | { 492 | // Install hook 493 | $this->artisan('hook:install', [ 494 | 'name' => 'composer-github-hook', 495 | 'version' => 'v1.0.0', 496 | ]); 497 | 498 | $this->artisan('hook:check'); 499 | 500 | $hooks = app('hooks')->hooks()->filter(function (Hook $hook) { 501 | return $hook->outdated(); 502 | }); 503 | 504 | $this->assertCount(1, $hooks); 505 | } 506 | 507 | public function test_provider_is_not_loaded_when_diabled() 508 | { 509 | // Install hook 510 | $this->artisan('hook:install', [ 511 | 'name' => 'composer-github-hook', 512 | ]); 513 | 514 | // Check that enabled 515 | $hook = app('hooks')->hook('composer-github-hook'); 516 | $this->assertFalse($hook->enabled); 517 | 518 | // Require files 519 | require_once base_path('vendor/composer-github-hook/src/ComposerGithubHookServiceProvider.php'); 520 | 521 | // Reload service providers 522 | app(\Larapack\Hooks\HooksServiceProvider::class, [ 523 | 'app' => app(), 524 | ])->registerHookProviders(); 525 | 526 | // Check if service provider has run 527 | $this->assertFalse(\ComposerGithubHook\ComposerGithubHookServiceProvider::$isBooted); 528 | $this->assertFalse(\ComposerGithubHook\ComposerGithubHookServiceProvider::$isRegistered); 529 | } 530 | 531 | public function test_alias_is_not_loaded_when_disabled() 532 | { 533 | // Install hook 534 | $this->artisan('hook:install', [ 535 | 'name' => 'composer-github-hook', 536 | ]); 537 | 538 | // Check that enabled 539 | $hook = app('hooks')->hook('composer-github-hook'); 540 | $this->assertFalse($hook->enabled); 541 | 542 | // Require files 543 | require_once base_path('vendor/composer-github-hook/src/ComposerGithubHookServiceProvider.php'); 544 | require_once base_path('vendor/composer-github-hook/src/TestAlias.php'); 545 | 546 | // Reload service providers 547 | app(\Larapack\Hooks\HooksServiceProvider::class, [ 548 | 'app' => app(), 549 | ])->registerHookProviders(); 550 | 551 | // Test if alias exists 552 | $this->assertFalse(class_exists(\Test::class)); 553 | } 554 | 555 | public function test_provider_is_loaded_when_enabled() 556 | { 557 | // Install hook 558 | $this->artisan('hook:install', [ 559 | 'name' => 'composer-github-hook', 560 | '--enable' => true, 561 | ]); 562 | 563 | // Check that enabled 564 | $hook = app('hooks')->hook('composer-github-hook'); 565 | $this->assertTrue($hook->enabled); 566 | 567 | // Require files 568 | require_once base_path('vendor/composer-github-hook/src/ComposerGithubHookServiceProvider.php'); 569 | 570 | // Reload service providers 571 | app(\Larapack\Hooks\HooksServiceProvider::class, [ 572 | 'app' => app(), 573 | ])->registerHookProviders(); 574 | 575 | // Check if service provider has run 576 | $this->assertTrue(\ComposerGithubHook\ComposerGithubHookServiceProvider::$isBooted); 577 | $this->assertTrue(\ComposerGithubHook\ComposerGithubHookServiceProvider::$isRegistered); 578 | } 579 | 580 | public function test_alias_is_loaded_when_enabled() 581 | { 582 | // Install hook 583 | $this->artisan('hook:install', [ 584 | 'name' => 'composer-github-hook', 585 | '--enable' => true, 586 | ]); 587 | 588 | // Check that enabled 589 | $hook = app('hooks')->hook('composer-github-hook'); 590 | $this->assertTrue($hook->enabled); 591 | 592 | // Require files 593 | require_once base_path('vendor/composer-github-hook/src/ComposerGithubHookServiceProvider.php'); 594 | require_once base_path('vendor/composer-github-hook/src/TestAlias.php'); 595 | 596 | // Reload service providers 597 | app(\Larapack\Hooks\HooksServiceProvider::class, [ 598 | 'app' => app(), 599 | ])->registerHookProviders(); 600 | 601 | // Test if alias exists and works 602 | $this->assertTrue(class_exists(\Test::class)); 603 | $this->assertEquals('bar', \Test::foo()); 604 | } 605 | 606 | public function test_dependencies_are_downloaded() 607 | { 608 | $filesystem = app(Filesystem::class); 609 | 610 | // Make sure dependency not already exists 611 | $this->assertDirectoryNotExists(base_path('vendor/marktopper/composer-hook-dependency-1')); 612 | 613 | // Install hook 614 | $this->artisan('hook:install', [ 615 | 'name' => 'composer-github-hook', 616 | ]); 617 | 618 | // Make sure dependency is now downloaded 619 | $this->assertDirectoryExists(base_path('vendor/marktopper/composer-hook-dependency-1')); 620 | } 621 | 622 | public function test_updating_updates_dependencies() 623 | { 624 | $filesystem = app(Filesystem::class); 625 | 626 | // Make sure dependency not already exists 627 | $this->assertDirectoryNotExists(base_path('vendor/marktopper/composer-hook-dependency-1')); 628 | $this->assertDirectoryNotExists(base_path('vendor/marktopper/composer-hook-dependency-2')); 629 | 630 | // Install hook 631 | $this->artisan('hook:install', [ 632 | 'name' => 'composer-github-hook', 633 | 'version' => 'v1.0.0', 634 | ]); 635 | 636 | // Make sure dependency is now downloaded 637 | $this->assertDirectoryExists(base_path('vendor/marktopper/composer-hook-dependency-1')); 638 | $this->assertDirectoryNotExists(base_path('vendor/marktopper/composer-hook-dependency-2')); 639 | 640 | Hooks::useVersionWildcardOnUpdate(); 641 | 642 | // Update hook 643 | $this->artisan('hook:update', [ 644 | 'name' => 'composer-github-hook', 645 | ]); 646 | 647 | // Make sure dependency is now downloaded 648 | $this->assertDirectoryExists(base_path('vendor/marktopper/composer-hook-dependency-1')); 649 | $this->assertDirectoryExists(base_path('vendor/marktopper/composer-hook-dependency-2')); 650 | } 651 | 652 | public function test_migrating_hook() 653 | { 654 | $filesystem = app(Filesystem::class); 655 | 656 | $this->assertFalse(Schema::hasTable('tests')); 657 | $this->assertMigrationHasNotRan('2018_01_19_000000_create_tests_table'); 658 | 659 | // Install hook 660 | $this->artisan('hook:install', [ 661 | 'name' => 'migrating-hook', 662 | 'version' => 'v1.0.0', 663 | ]); 664 | 665 | $this->assertTrue(Schema::hasTable('tests')); 666 | $this->assertMigrationHasRan('2018_01_19_000000_create_tests_table'); 667 | } 668 | 669 | public function test_installing_without_migrating_hook() 670 | { 671 | $filesystem = app(Filesystem::class); 672 | 673 | $this->assertFalse(Schema::hasTable('tests')); 674 | $this->assertMigrationHasNotRan('2018_01_19_000000_create_tests_table'); 675 | 676 | // Install hook 677 | $this->artisan('hook:install', [ 678 | 'name' => 'migrating-hook', 679 | 'version' => 'v1.0.0', 680 | '--no-migrate' => true, 681 | '--no-seed' => true, 682 | ]); 683 | 684 | $this->assertFalse(Schema::hasTable('tests')); 685 | $this->assertMigrationHasNotRan('2018_01_19_000000_create_tests_table'); 686 | } 687 | 688 | public function test_unmigrating_hook() 689 | { 690 | $filesystem = app(Filesystem::class); 691 | 692 | $this->assertFalse(Schema::hasTable('tests')); 693 | $this->assertMigrationHasNotRan('2018_01_19_000000_create_tests_table'); 694 | 695 | // Install hook 696 | $this->artisan('hook:install', [ 697 | 'name' => 'migrating-hook', 698 | 'version' => 'v1.0.0', 699 | ]); 700 | 701 | $this->assertTrue(Schema::hasTable('tests')); 702 | $this->assertMigrationHasRan('2018_01_19_000000_create_tests_table'); 703 | 704 | // Uninstall hook 705 | $this->artisan('hook:uninstall', [ 706 | 'name' => 'migrating-hook', 707 | ]); 708 | 709 | $this->assertFalse(Schema::hasTable('tests')); 710 | $this->assertMigrationHasNotRan('2018_01_19_000000_create_tests_table'); 711 | } 712 | 713 | public function test_uninstalling_without_unmigrating_hook() 714 | { 715 | $filesystem = app(Filesystem::class); 716 | 717 | $this->assertFalse(Schema::hasTable('tests')); 718 | $this->assertMigrationHasNotRan('2018_01_19_000000_create_tests_table'); 719 | 720 | // Install hook 721 | $this->artisan('hook:install', [ 722 | 'name' => 'migrating-hook', 723 | 'version' => 'v1.0.0', 724 | ]); 725 | 726 | $this->assertTrue(Schema::hasTable('tests')); 727 | $this->assertMigrationHasRan('2018_01_19_000000_create_tests_table'); 728 | 729 | // Uninstall hook 730 | $this->artisan('hook:uninstall', [ 731 | 'name' => 'migrating-hook', 732 | '--no-unmigrate' => true, 733 | ]); 734 | 735 | $this->assertTrue(Schema::hasTable('tests')); 736 | $this->assertMigrationHasRan('2018_01_19_000000_create_tests_table'); 737 | $this->assertEquals(0, DB::table('tests')->count()); 738 | } 739 | 740 | public function test_remigrating_hook_on_update() 741 | { 742 | $filesystem = app(Filesystem::class); 743 | 744 | $this->assertFalse(Schema::hasTable('tests')); 745 | $this->assertMigrationHasNotRan('2018_01_19_000000_create_tests_table'); 746 | $this->assertFalse(Schema::hasTable('another_tests')); 747 | $this->assertMigrationHasNotRan('2018_01_19_100000_create_another_tests_table'); 748 | 749 | // Install hook 750 | $this->artisan('hook:install', [ 751 | 'name' => 'migrating-hook', 752 | 'version' => 'v1.0.0', 753 | ]); 754 | 755 | $this->assertTrue(Schema::hasTable('tests')); 756 | $this->assertMigrationHasRan('2018_01_19_000000_create_tests_table'); 757 | 758 | $this->assertFalse(Schema::hasTable('another_tests')); 759 | $this->assertMigrationHasNotRan('2018_01_19_100000_create_another_tests_table'); 760 | 761 | // Install hook 762 | $this->artisan('hook:update', [ 763 | 'name' => 'migrating-hook', 764 | 'version' => 'v2.0.0', 765 | ]); 766 | 767 | $this->assertTrue(Schema::hasTable('tests')); 768 | $this->assertMigrationHasRan('2018_01_19_000000_create_tests_table'); 769 | $this->assertTrue(Schema::hasTable('another_tests')); 770 | $this->assertMigrationHasRan('2018_01_19_100000_create_another_tests_table'); 771 | } 772 | 773 | public function test_updating_without_remigrating_hook() 774 | { 775 | $filesystem = app(Filesystem::class); 776 | 777 | $this->assertFalse(Schema::hasTable('tests')); 778 | $this->assertMigrationHasNotRan('2018_01_19_000000_create_tests_table'); 779 | $this->assertFalse(Schema::hasTable('another_tests')); 780 | $this->assertMigrationHasNotRan('2018_01_19_100000_create_another_tests_table'); 781 | 782 | // Install hook 783 | $this->artisan('hook:install', [ 784 | 'name' => 'migrating-hook', 785 | 'version' => 'v1.0.0', 786 | ]); 787 | 788 | $this->assertTrue(Schema::hasTable('tests')); 789 | $this->assertMigrationHasRan('2018_01_19_000000_create_tests_table'); 790 | 791 | $this->assertFalse(Schema::hasTable('another_tests')); 792 | $this->assertMigrationHasNotRan('2018_01_19_100000_create_another_tests_table'); 793 | 794 | // Install hook 795 | $this->artisan('hook:update', [ 796 | 'name' => 'migrating-hook', 797 | 'version' => 'v2.0.0', 798 | '--no-migrate' => true, 799 | '--no-seed' => true, 800 | ]); 801 | 802 | $this->assertTrue(Schema::hasTable('tests')); 803 | $this->assertMigrationHasRan('2018_01_19_000000_create_tests_table'); 804 | $this->assertFalse(Schema::hasTable('another_tests')); 805 | $this->assertMigrationHasNotRan('2018_01_19_100000_create_another_tests_table'); 806 | } 807 | 808 | public function test_seeding_hook() 809 | { 810 | $filesystem = app(Filesystem::class); 811 | 812 | $this->assertFalse(Schema::hasTable('tests')); 813 | 814 | // Install hook 815 | $this->artisan('hook:install', [ 816 | 'name' => 'migrating-hook', 817 | 'version' => 'v1.0.0', 818 | ]); 819 | 820 | $this->assertTrue(Schema::hasTable('tests')); 821 | $this->assertEquals(3, DB::table('tests')->count()); 822 | } 823 | 824 | public function test_installing_without_seeding_hook() 825 | { 826 | $filesystem = app(Filesystem::class); 827 | 828 | $this->assertFalse(Schema::hasTable('tests')); 829 | 830 | // Install hook 831 | $this->artisan('hook:install', [ 832 | 'name' => 'migrating-hook', 833 | 'version' => 'v1.0.0', 834 | '--no-seed' => true, 835 | ]); 836 | 837 | $this->assertTrue(Schema::hasTable('tests')); 838 | $this->assertEquals(0, DB::table('tests')->count()); 839 | } 840 | 841 | public function test_unseeding_hook() 842 | { 843 | $filesystem = app(Filesystem::class); 844 | 845 | $this->assertFalse(Schema::hasTable('tests')); 846 | 847 | // Install hook 848 | $this->artisan('hook:install', [ 849 | 'name' => 'migrating-hook', 850 | 'version' => 'v1.0.0', 851 | ]); 852 | 853 | $this->assertTrue(Schema::hasTable('tests')); 854 | $this->assertEquals(3, DB::table('tests')->count()); 855 | 856 | // Uninstall hook 857 | $this->artisan('hook:uninstall', [ 858 | 'name' => 'migrating-hook', 859 | '--no-unmigrate' => true, 860 | ]); 861 | 862 | $this->assertTrue(Schema::hasTable('tests')); 863 | $this->assertEquals(0, DB::table('tests')->count()); 864 | } 865 | 866 | public function test_uninstalling_without_unseeding() 867 | { 868 | $filesystem = app(Filesystem::class); 869 | 870 | $this->assertFalse(Schema::hasTable('tests')); 871 | 872 | // Install hook 873 | $this->artisan('hook:install', [ 874 | 'name' => 'migrating-hook', 875 | 'version' => 'v1.0.0', 876 | ]); 877 | 878 | $this->assertTrue(Schema::hasTable('tests')); 879 | $this->assertEquals(3, DB::table('tests')->count()); 880 | 881 | // Uninstall hook 882 | $this->artisan('hook:uninstall', [ 883 | 'name' => 'migrating-hook', 884 | '--no-unmigrate' => true, 885 | '--no-unseed' => true, 886 | ]); 887 | 888 | $this->assertTrue(Schema::hasTable('tests')); 889 | $this->assertEquals(3, DB::table('tests')->count()); 890 | } 891 | 892 | public function test_reseeding_on_update() 893 | { 894 | $filesystem = app(Filesystem::class); 895 | 896 | $this->assertFalse(Schema::hasTable('tests')); 897 | 898 | // Install hook 899 | $this->artisan('hook:install', [ 900 | 'name' => 'migrating-hook', 901 | 'version' => 'v1.0.0', 902 | ]); 903 | 904 | $this->assertTrue(Schema::hasTable('tests')); 905 | $this->assertEquals(3, DB::table('tests')->count()); 906 | 907 | // Update hook 908 | $this->artisan('hook:update', [ 909 | 'name' => 'migrating-hook', 910 | 'version' => 'v2.0.0', 911 | ]); 912 | 913 | $this->assertTrue(Schema::hasTable('tests')); 914 | $this->assertEquals(3, DB::table('tests')->count()); 915 | $this->assertTrue(Schema::hasTable('another_tests')); 916 | $this->assertEquals(3, DB::table('another_tests')->count()); 917 | } 918 | 919 | public function test_updating_without_reseeding() 920 | { 921 | $filesystem = app(Filesystem::class); 922 | 923 | $this->assertFalse(Schema::hasTable('tests')); 924 | 925 | // Install hook 926 | $this->artisan('hook:install', [ 927 | 'name' => 'migrating-hook', 928 | 'version' => 'v1.0.0', 929 | ]); 930 | 931 | $this->assertTrue(Schema::hasTable('tests')); 932 | $this->assertEquals(3, DB::table('tests')->count()); 933 | 934 | // Update hook 935 | $this->artisan('hook:update', [ 936 | 'name' => 'migrating-hook', 937 | 'version' => 'v2.0.0', 938 | '--no-seed' => true, 939 | ]); 940 | 941 | $this->assertTrue(Schema::hasTable('tests')); 942 | $this->assertEquals(3, DB::table('tests')->count()); 943 | $this->assertTrue(Schema::hasTable('another_tests')); 944 | $this->assertEquals(0, DB::table('another_tests')->count()); 945 | } 946 | 947 | public function test_publishing_assets() 948 | { 949 | $filesystem = app(Filesystem::class); 950 | 951 | $this->assertFalse($filesystem->exists(base_path('public/vendor'))); 952 | 953 | // Install hook 954 | $this->artisan('hook:install', [ 955 | 'name' => 'migrating-hook', 956 | 'version' => 'v1.0.0', 957 | ]); 958 | 959 | $this->assertTrue($filesystem->exists(base_path('public/vendor/migration-hook/assets'))); 960 | $this->assertTrue($filesystem->exists(base_path('public/vendor/migration-hook/assets/script.js'))); 961 | $this->assertEquals("alert('I am alive!');\n", $filesystem->get( 962 | base_path('public/vendor/migration-hook/assets/script.js') 963 | )); 964 | } 965 | 966 | public function test_installing_without_publishing_assets() 967 | { 968 | $filesystem = app(Filesystem::class); 969 | 970 | $this->assertFalse($filesystem->exists(base_path('public/vendor'))); 971 | 972 | // Install hook 973 | $this->artisan('hook:install', [ 974 | 'name' => 'migrating-hook', 975 | 'version' => 'v1.0.0', 976 | '--no-publish' => true, 977 | ]); 978 | 979 | $this->assertFalse($filesystem->exists(base_path('public/vendor'))); 980 | } 981 | 982 | public function test_unpublishing_assets() 983 | { 984 | $filesystem = app(Filesystem::class); 985 | 986 | $this->assertFalse($filesystem->exists(base_path('public/vendor'))); 987 | 988 | // Install hook 989 | $this->artisan('hook:install', [ 990 | 'name' => 'migrating-hook', 991 | 'version' => 'v1.0.0', 992 | ]); 993 | 994 | $this->assertTrue($filesystem->exists(base_path('public/vendor/migration-hook/assets'))); 995 | $this->assertTrue($filesystem->exists(base_path('public/vendor/migration-hook/assets/script.js'))); 996 | $this->assertEquals("alert('I am alive!');\n", $filesystem->get( 997 | base_path('public/vendor/migration-hook/assets/script.js') 998 | )); 999 | 1000 | // Uninstall hook 1001 | $this->artisan('hook:uninstall', [ 1002 | 'name' => 'migrating-hook', 1003 | ]); 1004 | 1005 | $this->assertFalse($filesystem->exists(base_path('public/vendor/migration-hook/assets/script.js'))); 1006 | } 1007 | 1008 | public function test_unpublishing_assets_without_removing_other_files_in_folder() 1009 | { 1010 | $filesystem = app(Filesystem::class); 1011 | 1012 | $this->assertFalse($filesystem->exists(base_path('public/vendor'))); 1013 | 1014 | // Install hook 1015 | $this->artisan('hook:install', [ 1016 | 'name' => 'migrating-hook', 1017 | 'version' => 'v1.0.0', 1018 | ]); 1019 | 1020 | $this->assertTrue($filesystem->exists(base_path('public/vendor/migration-hook/assets'))); 1021 | $this->assertTrue($filesystem->exists(base_path('public/vendor/migration-hook/assets/script.js'))); 1022 | $this->assertEquals("alert('I am alive!');\n", $filesystem->get( 1023 | base_path('public/vendor/migration-hook/assets/script.js') 1024 | )); 1025 | 1026 | $filesystem->put( 1027 | base_path('public/vendor/migration-hook/assets/test.js'), 1028 | "alert('This is just a test!');\n" 1029 | ); 1030 | 1031 | // Uninstall hook 1032 | $this->artisan('hook:uninstall', [ 1033 | 'name' => 'migrating-hook', 1034 | ]); 1035 | 1036 | $this->assertFalse($filesystem->exists(base_path('public/vendor/migration-hook/assets/script.js'))); 1037 | $this->assertTrue($filesystem->exists(base_path('public/vendor/migration-hook/assets/test.js'))); 1038 | $this->assertEquals("alert('This is just a test!');\n", $filesystem->get( 1039 | base_path('public/vendor/migration-hook/assets/test.js') 1040 | )); 1041 | } 1042 | 1043 | public function test_uninstalling_without_unpublishing_assets() 1044 | { 1045 | $filesystem = app(Filesystem::class); 1046 | 1047 | $this->assertFalse($filesystem->exists(base_path('public/vendor'))); 1048 | 1049 | // Install hook 1050 | $this->artisan('hook:install', [ 1051 | 'name' => 'migrating-hook', 1052 | 'version' => 'v1.0.0', 1053 | ]); 1054 | 1055 | $this->assertTrue($filesystem->exists(base_path('public/vendor/migration-hook/assets'))); 1056 | $this->assertTrue($filesystem->exists(base_path('public/vendor/migration-hook/assets/script.js'))); 1057 | $this->assertEquals("alert('I am alive!');\n", $filesystem->get( 1058 | base_path('public/vendor/migration-hook/assets/script.js') 1059 | )); 1060 | 1061 | // Uninstall hook 1062 | $this->artisan('hook:uninstall', [ 1063 | 'name' => 'migrating-hook', 1064 | '--no-unpublish' => true, 1065 | ]); 1066 | 1067 | $this->assertTrue($filesystem->exists(base_path('public/vendor/migration-hook/assets'))); 1068 | $this->assertTrue($filesystem->exists(base_path('public/vendor/migration-hook/assets/script.js'))); 1069 | $this->assertEquals("alert('I am alive!');\n", $filesystem->get( 1070 | base_path('public/vendor/migration-hook/assets/script.js') 1071 | )); 1072 | } 1073 | 1074 | public function test_republishing_assets_on_update() 1075 | { 1076 | $filesystem = app(Filesystem::class); 1077 | 1078 | $this->assertFalse($filesystem->exists(base_path('public/vendor'))); 1079 | 1080 | // Install hook 1081 | $this->artisan('hook:install', [ 1082 | 'name' => 'migrating-hook', 1083 | 'version' => 'v1.0.0', 1084 | ]); 1085 | 1086 | $this->assertTrue($filesystem->exists(base_path('public/vendor/migration-hook/assets'))); 1087 | $this->assertTrue($filesystem->exists(base_path('public/vendor/migration-hook/assets/script.js'))); 1088 | $this->assertEquals("alert('I am alive!');\n", $filesystem->get( 1089 | base_path('public/vendor/migration-hook/assets/script.js') 1090 | )); 1091 | 1092 | // Update hook 1093 | $this->artisan('hook:update', [ 1094 | 'name' => 'migrating-hook', 1095 | 'version' => 'v2.0.0', 1096 | ]); 1097 | 1098 | $this->assertTrue($filesystem->exists(base_path('public/vendor/migration-hook/assets/script.js'))); 1099 | $this->assertTrue($filesystem->exists(base_path('public/vendor/migration-hook/assets/another.js'))); 1100 | $this->assertEquals("alert('I am still alive!');\n", $filesystem->get( 1101 | base_path('public/vendor/migration-hook/assets/script.js') 1102 | )); 1103 | $this->assertEquals("alert('I am another file!');\n", $filesystem->get( 1104 | base_path('public/vendor/migration-hook/assets/another.js') 1105 | )); 1106 | } 1107 | 1108 | public function test_updating_without_republishing_assets() 1109 | { 1110 | $filesystem = app(Filesystem::class); 1111 | 1112 | $this->assertFalse($filesystem->exists(base_path('public/vendor'))); 1113 | 1114 | // Install hook 1115 | $this->artisan('hook:install', [ 1116 | 'name' => 'migrating-hook', 1117 | 'version' => 'v1.0.0', 1118 | ]); 1119 | 1120 | $this->assertTrue($filesystem->exists(base_path('public/vendor/migration-hook/assets'))); 1121 | $this->assertTrue($filesystem->exists(base_path('public/vendor/migration-hook/assets/script.js'))); 1122 | $this->assertEquals("alert('I am alive!');\n", $filesystem->get( 1123 | base_path('public/vendor/migration-hook/assets/script.js') 1124 | )); 1125 | 1126 | // Update hook 1127 | $this->artisan('hook:update', [ 1128 | 'name' => 'migrating-hook', 1129 | 'version' => 'v2.0.0', 1130 | '--no-publish' => true, 1131 | ]); 1132 | 1133 | $this->assertTrue($filesystem->exists(base_path('public/vendor/migration-hook/assets/script.js'))); 1134 | $this->assertFalse($filesystem->exists(base_path('public/vendor/migration-hook/assets/another.js'))); 1135 | $this->assertEquals("alert('I am alive!');\n", $filesystem->get( 1136 | base_path('public/vendor/migration-hook/assets/script.js') 1137 | )); 1138 | } 1139 | 1140 | public function test_republishing_assets_on_update_with_custom_changed_files() 1141 | { 1142 | $filesystem = app(Filesystem::class); 1143 | 1144 | $this->assertFalse($filesystem->exists(base_path('public/vendor'))); 1145 | 1146 | // Install hook 1147 | $this->artisan('hook:install', [ 1148 | 'name' => 'migrating-hook', 1149 | 'version' => 'v1.0.0', 1150 | ]); 1151 | 1152 | $this->assertTrue($filesystem->exists(base_path('public/vendor/migration-hook/assets'))); 1153 | $this->assertTrue($filesystem->exists(base_path('public/vendor/migration-hook/assets/script.js'))); 1154 | $this->assertEquals("alert('I am alive!');\n", $filesystem->get( 1155 | base_path('public/vendor/migration-hook/assets/script.js') 1156 | )); 1157 | 1158 | $filesystem->put( 1159 | base_path('public/vendor/migration-hook/assets/script.js'), 1160 | "alert('Am I still alive?');\n" 1161 | ); 1162 | 1163 | // Update hook 1164 | $this->artisan('hook:update', [ 1165 | 'name' => 'migrating-hook', 1166 | 'version' => 'v2.0.0', 1167 | ]); 1168 | 1169 | $this->assertTrue($filesystem->exists(base_path('public/vendor/migration-hook/assets/script.js'))); 1170 | $this->assertTrue($filesystem->exists(base_path('public/vendor/migration-hook/assets/another.js'))); 1171 | $this->assertEquals("alert('Am I still alive?');\n", $filesystem->get( 1172 | base_path('public/vendor/migration-hook/assets/script.js') 1173 | )); 1174 | $this->assertEquals("alert('I am another file!');\n", $filesystem->get( 1175 | base_path('public/vendor/migration-hook/assets/another.js') 1176 | )); 1177 | } 1178 | 1179 | public function test_force_republishing_assets_on_update_with_custom_changed_files() 1180 | { 1181 | $filesystem = app(Filesystem::class); 1182 | 1183 | $this->assertFalse($filesystem->exists(base_path('public/vendor'))); 1184 | 1185 | // Install hook 1186 | $this->artisan('hook:install', [ 1187 | 'name' => 'migrating-hook', 1188 | 'version' => 'v1.0.0', 1189 | ]); 1190 | 1191 | $this->assertTrue($filesystem->exists(base_path('public/vendor/migration-hook/assets'))); 1192 | $this->assertTrue($filesystem->exists(base_path('public/vendor/migration-hook/assets/script.js'))); 1193 | $this->assertEquals("alert('I am alive!');\n", $filesystem->get( 1194 | base_path('public/vendor/migration-hook/assets/script.js') 1195 | )); 1196 | 1197 | $filesystem->put( 1198 | base_path('public/vendor/migration-hook/assets/script.js'), 1199 | "alert('Am I still alive?');\n" 1200 | ); 1201 | 1202 | // Update hook 1203 | $this->artisan('hook:update', [ 1204 | 'name' => 'migrating-hook', 1205 | 'version' => 'v2.0.0', 1206 | '--force' => true, 1207 | ]); 1208 | 1209 | $this->assertTrue($filesystem->exists(base_path('public/vendor/migration-hook/assets/script.js'))); 1210 | $this->assertTrue($filesystem->exists(base_path('public/vendor/migration-hook/assets/another.js'))); 1211 | $this->assertEquals("alert('I am still alive!');\n", $filesystem->get( 1212 | base_path('public/vendor/migration-hook/assets/script.js') 1213 | )); 1214 | $this->assertEquals("alert('I am another file!');\n", $filesystem->get( 1215 | base_path('public/vendor/migration-hook/assets/another.js') 1216 | )); 1217 | } 1218 | 1219 | public function test_hook_migrating_single_file() 1220 | { 1221 | $filesystem = app(Filesystem::class); 1222 | 1223 | $this->assertFalse(Schema::hasTable('tests')); 1224 | $this->assertMigrationHasNotRan('2018_01_21_000000_create_tests_table'); 1225 | 1226 | // Install hook 1227 | $this->artisan('hook:install', [ 1228 | 'name' => 'single-migrating-hook', 1229 | 'version' => 'v1.0.0', 1230 | ]); 1231 | 1232 | $this->assertTrue(Schema::hasTable('tests')); 1233 | $this->assertMigrationHasRan('2018_01_21_000000_create_tests_table'); 1234 | $this->assertFalse(Schema::hasTable('another_tests')); 1235 | $this->assertMigrationHasNotRan('2018_01_21_000000_create_another_tests_table'); 1236 | } 1237 | 1238 | public function test_hook_unmigrating_single_file() 1239 | { 1240 | $filesystem = app(Filesystem::class); 1241 | 1242 | $this->assertFalse(Schema::hasTable('tests')); 1243 | $this->assertMigrationHasNotRan('2018_01_21_000000_create_tests_table'); 1244 | 1245 | // Install hook 1246 | $this->artisan('hook:install', [ 1247 | 'name' => 'single-migrating-hook', 1248 | 'version' => 'v1.0.0', 1249 | ]); 1250 | 1251 | $this->assertTrue(Schema::hasTable('tests')); 1252 | $this->assertMigrationHasRan('2018_01_21_000000_create_tests_table'); 1253 | $this->assertFalse(Schema::hasTable('another_tests')); 1254 | $this->assertMigrationHasNotRan('2018_01_21_000000_create_another_tests_table'); 1255 | 1256 | // Uninstall hook 1257 | $this->artisan('hook:uninstall', [ 1258 | 'name' => 'single-migrating-hook', 1259 | ]); 1260 | 1261 | $this->assertFalse(Schema::hasTable('tests')); 1262 | $this->assertMigrationHasNOtRan('2018_01_21_000000_create_tests_table'); 1263 | $this->assertFalse(Schema::hasTable('another_tests')); 1264 | $this->assertMigrationHasNotRan('2018_01_21_000000_create_another_tests_table'); 1265 | } 1266 | 1267 | public function test_hook_seeding_single_file() 1268 | { 1269 | $filesystem = app(Filesystem::class); 1270 | 1271 | $this->assertFalse(Schema::hasTable('tests')); 1272 | $this->assertMigrationHasNotRan('2018_01_21_000000_create_tests_table'); 1273 | 1274 | // Install hook 1275 | $this->artisan('hook:install', [ 1276 | 'name' => 'single-migrating-hook', 1277 | 'version' => 'v1.0.0', 1278 | ]); 1279 | 1280 | $this->assertTrue(Schema::hasTable('tests')); 1281 | $this->assertMigrationHasRan('2018_01_21_000000_create_tests_table'); 1282 | $this->assertEquals(3, DB::table('tests')->count()); 1283 | $this->assertFalse(Schema::hasTable('another_tests')); 1284 | $this->assertMigrationHasNotRan('2018_01_21_000000_create_another_tests_table'); 1285 | } 1286 | 1287 | public function test_hook_unseeding_single_file() 1288 | { 1289 | $filesystem = app(Filesystem::class); 1290 | 1291 | $this->assertFalse(Schema::hasTable('tests')); 1292 | $this->assertMigrationHasNotRan('2018_01_21_000000_create_tests_table'); 1293 | 1294 | // Install hook 1295 | $this->artisan('hook:install', [ 1296 | 'name' => 'single-migrating-hook', 1297 | 'version' => 'v1.0.0', 1298 | ]); 1299 | 1300 | $this->assertTrue(Schema::hasTable('tests')); 1301 | $this->assertMigrationHasRan('2018_01_21_000000_create_tests_table'); 1302 | $this->assertEquals(3, DB::table('tests')->count()); 1303 | $this->assertFalse(Schema::hasTable('another_tests')); 1304 | $this->assertMigrationHasNotRan('2018_01_21_000000_create_another_tests_table'); 1305 | 1306 | // Uninstall hook 1307 | $this->artisan('hook:uninstall', [ 1308 | 'name' => 'single-migrating-hook', 1309 | '--no-unmigrate' => true, 1310 | ]); 1311 | 1312 | $this->assertTrue(Schema::hasTable('tests')); 1313 | $this->assertMigrationHasRan('2018_01_21_000000_create_tests_table'); 1314 | $this->assertEquals(0, DB::table('tests')->count()); 1315 | $this->assertFalse(Schema::hasTable('another_tests')); 1316 | $this->assertMigrationHasNotRan('2018_01_21_000000_create_another_tests_table'); 1317 | } 1318 | 1319 | public function test_hook_publishing_single_file() 1320 | { 1321 | $filesystem = app(Filesystem::class); 1322 | 1323 | $this->assertFalse($filesystem->exists(base_path('public/vendor'))); 1324 | 1325 | // Install hook 1326 | $this->artisan('hook:install', [ 1327 | 'name' => 'single-migrating-hook', 1328 | 'version' => 'v1.0.0', 1329 | ]); 1330 | 1331 | $this->assertTrue($filesystem->exists(base_path('public/vendor/single-migrating-hook/assets/scripts'))); 1332 | $this->assertTrue($filesystem->exists(base_path('public/vendor/single-migrating-hook/assets/scripts/alert.js'))); 1333 | $this->assertEquals("alert('Test!');\n", $filesystem->get( 1334 | base_path('public/vendor/single-migrating-hook/assets/scripts/alert.js') 1335 | )); 1336 | 1337 | $this->assertFalse($filesystem->exists(base_path('public/vendor/single-migrating-hook/assets/scripts/another-test.js'))); 1338 | } 1339 | 1340 | public function test_hook_unpublishing_single_file() 1341 | { 1342 | $filesystem = app(Filesystem::class); 1343 | 1344 | $this->assertFalse($filesystem->exists(base_path('public/vendor'))); 1345 | 1346 | // Install hook 1347 | $this->artisan('hook:install', [ 1348 | 'name' => 'single-migrating-hook', 1349 | 'version' => 'v1.0.0', 1350 | ]); 1351 | 1352 | $this->assertTrue($filesystem->exists(base_path('public/vendor/single-migrating-hook/assets/scripts'))); 1353 | $this->assertTrue($filesystem->exists(base_path('public/vendor/single-migrating-hook/assets/scripts/alert.js'))); 1354 | $this->assertEquals("alert('Test!');\n", $filesystem->get( 1355 | base_path('public/vendor/single-migrating-hook/assets/scripts/alert.js') 1356 | )); 1357 | 1358 | $this->assertFalse($filesystem->exists(base_path('public/vendor/single-migrating-hook/assets/scripts/another-test.js'))); 1359 | 1360 | $filesystem->put(base_path('public/vendor/single-migrating-hook/assets/scripts/another-test.js'), "alert('Another test!');\n"); 1361 | 1362 | // Uninstall hook 1363 | $this->artisan('hook:uninstall', [ 1364 | 'name' => 'single-migrating-hook', 1365 | ]); 1366 | 1367 | $this->assertTrue($filesystem->exists(base_path('public/vendor/single-migrating-hook/assets/scripts'))); 1368 | $this->assertFalse($filesystem->exists(base_path('public/vendor/single-migrating-hook/assets/scripts/alert.js'))); 1369 | $this->assertTrue($filesystem->exists(base_path('public/vendor/single-migrating-hook/assets/scripts/another-test.js'))); 1370 | } 1371 | 1372 | protected function assertMigrationHasRan($name) 1373 | { 1374 | return $this->assertTrue( 1375 | DB::table('migrations')->where('migration', $name)->count() == 1 1376 | ); 1377 | } 1378 | 1379 | protected function assertMigrationHasNotRan($name) 1380 | { 1381 | return $this->assertFalse( 1382 | DB::table('migrations')->where('migration', $name)->count() == 1 1383 | ); 1384 | } 1385 | } 1386 | -------------------------------------------------------------------------------- /tests/TestCase.php: -------------------------------------------------------------------------------- 1 | deleteDirectory(base_path('hooks')); 27 | 28 | // Cleanup published files 29 | $filesystem->deleteDirectory(base_path('public/vendor')); 30 | 31 | // Clear old hooks 32 | $hook = app(Hooks::class); 33 | $hook->readJsonFile(); 34 | 35 | // Delete testbench's fixures tests folder 36 | $filesystem->deleteDirectory(base_path('tests')); 37 | 38 | // Create tests folder 39 | $filesystem->makeDirectory(base_path('tests')); 40 | file_put_contents(base_path('tests/TestCase.php'), 'set('repositories', []); 45 | $composer->set('minimum-stability', 'stable'); 46 | $composer->set('require', [ 47 | 'laravel/framework' => $composer->get('require.laravel/framework'), 48 | ]); 49 | $composer->save(); 50 | $filesystem->delete(base_path('composer.lock')); 51 | 52 | // Cleanup vendor 53 | $filesystem->deleteDirectory(base_path('vendor')); 54 | $filesystem->makeDirectory(base_path('vendor')); 55 | 56 | // Setup Hook repository 57 | $this->artisan('hook:setup', [ 58 | '--url' => env('HOOKS_COMPOSER_REPOSITORY', static::COMPOSER_REPOSITORY), 59 | ]); 60 | 61 | // Reload JSON files 62 | app(Hooks::class)->readJsonFile(); 63 | 64 | // Migrate 65 | $this->artisan('migrate'); 66 | } 67 | 68 | public function tearDown(): void 69 | { 70 | // Cleanup old hooks before testing 71 | app(Filesystem::class)->deleteDirectory(base_path('hooks')); 72 | 73 | parent::tearDown(); 74 | } 75 | 76 | /** 77 | * Define environment setup. 78 | * 79 | * @param \Illuminate\Foundation\Application $app 80 | * 81 | * @return void 82 | */ 83 | protected function getEnvironmentSetUp($app) 84 | { 85 | // Setup default database to use sqlite :memory: 86 | $app['config']->set('database.default', 'testbench'); 87 | $app['config']->set('database.connections.testbench', [ 88 | 'driver' => 'sqlite', 89 | 'database' => ':memory:', 90 | 'prefix' => '', 91 | ]); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /tests/bootstrap.php: -------------------------------------------------------------------------------- 1 | increments('id'); 18 | 19 | $table->string('name'); 20 | 21 | $table->timestamps(); 22 | }); 23 | } 24 | 25 | /** 26 | * Reverse the migrations. 27 | * 28 | * @return void 29 | */ 30 | public function down() 31 | { 32 | Schema::dropIfExists('local_test_hook'); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /tests/fixtures/resources/database/seeders/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/larapack/hooks/ce2c8c078a56036c357f26036174412cb9059f8e/tests/fixtures/resources/database/seeders/.gitkeep -------------------------------------------------------------------------------- /tests/fixtures/resources/database/seeders/LocalTestHookTableSeeder.php: -------------------------------------------------------------------------------- 1 | count() > 0) { 17 | return; 18 | } 19 | 20 | DB::table('local_test_hook')->insert([ 21 | ['name' => 'foo'], 22 | ['name' => 'bar'], 23 | ['name' => 'baz'], 24 | ]); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/fixtures/resources/database/unseeders/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/larapack/hooks/ce2c8c078a56036c357f26036174412cb9059f8e/tests/fixtures/resources/database/unseeders/.gitkeep -------------------------------------------------------------------------------- /tests/fixtures/resources/database/unseeders/LocalTestHookTableUnseeder.php: -------------------------------------------------------------------------------- 1 | whereIn('name', ['foo', 'bar', 'baz']) 23 | ->delete(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /tests/fixtures/src/LocalTestHook.php: -------------------------------------------------------------------------------- 1 |