├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── composer.json ├── config └── updater.php ├── database └── factories │ └── ModelFactory.php ├── renovate.json ├── resources └── views │ └── .gitkeep └── src ├── Commands ├── CheckCommand.php └── UpdaterCommand.php ├── Contracts ├── Pipeline.php └── Repository.php ├── Events ├── NewVersionAvailable.php ├── UpdateFailed.php └── UpdatedSuccessfully.php ├── Exceptions ├── GitFailedException.php └── GithubConfigException.php ├── Facades └── Updater.php ├── Helpers ├── Git.php └── Helper.php ├── Pipelines ├── ArtisanCallCacheClearPipe.php ├── ArtisanCallConfigClearPipe.php ├── ArtisanCallMigratePipe.php ├── ArtisanCallOptimizePipe.php ├── ArtisanCallRouteClearPipe.php ├── ArtisanCallViewClearPipe.php ├── GitPipe.php └── SeedersPipe.php ├── RepositorySource └── GithubRepository.php ├── Updater.php └── UpdaterServiceProvider.php /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to `laravel-updater` will be documented in this file. 4 | 5 | ## v1.3.0 - 2025-04-01 6 | 7 | ### What's Changed 8 | 9 | * Bump aglipanci/laravel-pint-action from 2.4 to 2.5 by @dependabot in https://github.com/salahhusa9/laravel-updater/pull/62 10 | * Update dependency illuminate/contracts to **v12** by @renovate in https://github.com/salahhusa9/laravel-updater/pull/63 11 | * Update dependency node to v22 by @renovate in https://github.com/salahhusa9/laravel-updater/pull/65 12 | * chore(deps): update dependency orchestra/testbench to v10 by @renovate in https://github.com/salahhusa9/laravel-updater/pull/64 13 | 14 | > Thank you for using this package! ❤️ 15 | Consider supporting my work: 16 | https://github.com/sponsors/salahhusa9 17 | 18 | **Full Changelog**: https://github.com/salahhusa9/laravel-updater/compare/v1.2.4...v1.3.0 19 | 20 | ## v1.2.4 - 2025-01-27 21 | 22 | ### What's Changed 23 | 24 | * Update dependabot/fetch-metadata action to v2.3.0 by @renovate in https://github.com/salahhusa9/laravel-updater/pull/58 25 | * Update Updater.php to merge before and after update pipelines with existing pipelines by @salahhusa9 in https://github.com/salahhusa9/laravel-updater/pull/60 26 | 27 | Thank you for using this package! ❤️ 28 | Consider supporting my work: 29 | https://github.com/sponsors/salahhusa9 30 | 31 | **Full Changelog**: https://github.com/salahhusa9/laravel-updater/compare/v1.2.3...v1.2.4 32 | 33 | ## v1.2.3 - 2024-07-17 34 | 35 | ### What's Changed 36 | 37 | * Update dependabot/fetch-metadata action to v2.2.0 by @renovate in https://github.com/salahhusa9/laravel-updater/pull/52 38 | * [Add sponsor message and link in Update Command](https://github.com/sponsors/salahhusa9) 39 | 40 | > Thank you for using this package! ❤️ 41 | Consider supporting my work: 42 | https://github.com/sponsors/salahhusa9 43 | 44 | **Full Changelog**: https://github.com/salahhusa9/laravel-updater/compare/v1.2.2...v1.2.3 45 | 46 | ## v1.2.2 - 2024-06-25 47 | 48 | **Full Changelog**: https://github.com/salahhusa9/laravel-updater/compare/v1.2.1...v1.2.2 49 | 50 | ## v1.2.1 - 2024-06-08 51 | 52 | ### What's Changed 53 | 54 | * Update laravel in github action by @salahhusa9 in https://github.com/salahhusa9/laravel-updater/pull/44 55 | * Bump aglipanci/laravel-pint-action from 2.3.1 to 2.4 by @dependabot in https://github.com/salahhusa9/laravel-updater/pull/45 56 | * Update dependabot/fetch-metadata action to v2.1.0 by @renovate in https://github.com/salahhusa9/laravel-updater/pull/46 57 | * Remove symfony component process executable finder by @salahhusa9 in https://github.com/salahhusa9/laravel-updater/pull/50 58 | 59 | **Full Changelog**: https://github.com/salahhusa9/laravel-updater/compare/v1.2.0...v1.2.1 60 | 61 | ## v1.2.0 - 2024-04-01 62 | 63 | ### What's Changed 64 | 65 | * Git checkout throw away local modifications by @salahhusa9 in https://github.com/salahhusa9/laravel-updater/pull/43 66 | 67 | * Update dependency orchestra/testbench to v9 by @renovate in https://github.com/salahhusa9/laravel-updater/pull/39 68 | 69 | * Update dependabot/fetch-metadata action to v1.7.0 by @renovate in https://github.com/salahhusa9/laravel-updater/pull/40 70 | 71 | * Update dependabot/fetch-metadata action to v2 by @renovate in https://github.com/salahhusa9/laravel-updater/pull/41 72 | 73 | 74 | **Full Changelog**: https://github.com/salahhusa9/laravel-updater/compare/v1.1.0...v1.2.0 75 | 76 | ## v1.1.0 - 2024-03-12 77 | 78 | ### What's Changed 79 | 80 | * Add support of Laravel 11 by @salahhusa9 in https://github.com/salahhusa9/laravel-updater/pull/38 81 | 82 | **Full Changelog**: https://github.com/salahhusa9/laravel-updater/compare/v1.0.2...v1.1.0 83 | 84 | ## v1.0.2 - 2024-02-10 85 | 86 | ### What's Changed 87 | 88 | * new ui output by @salahhusa9 in https://github.com/salahhusa9/laravel-updater/pull/37 89 | 90 | **Full Changelog**: https://github.com/salahhusa9/laravel-updater/compare/v1.0.1...v1.0.2 91 | 92 | ## v1.0.1 - 2024-02-03 93 | 94 | ### What's Changed 95 | 96 | * Update actions/upload-pages-artifact action to v3 by @renovate in https://github.com/salahhusa9/laravel-updater/pull/28 97 | * Update actions/deploy-pages action to v4 by @renovate in https://github.com/salahhusa9/laravel-updater/pull/27 98 | * Bump aglipanci/laravel-pint-action from 2.3.0 to 2.3.1 by @dependabot in https://github.com/salahhusa9/laravel-updater/pull/30 99 | * remove migration file and in configure Package by @salahhusa9 in https://github.com/salahhusa9/laravel-updater/pull/36 100 | * Bump actions/cache from 3 to 4 by @dependabot in https://github.com/salahhusa9/laravel-updater/pull/32 101 | * [Update exception classes to use RuntimeException instead of Exception](https://github.com/salahhusa9/laravel-updater/commit/705485c97efaa161da81b3cc825e2b20c1f43d6f) 102 | 103 | **Full Changelog**: https://github.com/salahhusa9/laravel-updater/compare/v1.0.0...v1.0.1 104 | 105 | ## Laravel Updater v1 - 2023-11-21 106 | 107 | ### What's Changed 108 | 109 | - Update actions/setup-node action to v4 by @renovate in https://github.com/salahhusa9/laravel-updater/pull/14 110 | - Git failed exception by @salahhusa9 in https://github.com/salahhusa9/laravel-updater/pull/17 111 | - Tests pipelines by @salahhusa9 in https://github.com/salahhusa9/laravel-updater/pull/18 112 | - Tests Repository Source by @salahhusa9 in https://github.com/salahhusa9/laravel-updater/pull/19 113 | - Command test by @salahhusa9 in https://github.com/salahhusa9/laravel-updater/pull/20 114 | - updater facade tests by @salahhusa9 in https://github.com/salahhusa9/laravel-updater/pull/21 115 | - Remove Git Pull in update by @salahhusa9 in https://github.com/salahhusa9/laravel-updater/pull/22 116 | 117 | **Full Changelog**: https://github.com/salahhusa9/laravel-updater/compare/v0.0.1...v1.0.0 118 | 119 | ## Laravel Updater Beta - 2023-10-31 120 | 121 | ### What's Changed 122 | 123 | - Bump aglipanci/laravel-pint-action from 2.2.0 to 2.3.0 by @dependabot in https://github.com/salahhusa9/laravel-updater/pull/1 124 | - Patch 1 by @salahhusa9 in https://github.com/salahhusa9/laravel-updater/pull/5 125 | - Pipelines by @salahhusa9 in https://github.com/salahhusa9/laravel-updater/pull/6 126 | - Configure Renovate by @renovate in https://github.com/salahhusa9/laravel-updater/pull/4 127 | - Bump stefanzweifel/git-auto-commit-action from 4 to 5 by @dependabot in https://github.com/salahhusa9/laravel-updater/pull/2 128 | - Bump actions/checkout from 3 to 4 by @dependabot in https://github.com/salahhusa9/laravel-updater/pull/3 129 | - Interface pipeline by @salahhusa9 in https://github.com/salahhusa9/laravel-updater/pull/10 130 | - Fun docs by @salahhusa9 in https://github.com/salahhusa9/laravel-updater/pull/11 131 | - Test by @salahhusa9 in https://github.com/salahhusa9/laravel-updater/pull/12 132 | - Output in run by @salahhusa9 in https://github.com/salahhusa9/laravel-updater/pull/13 133 | 134 | ### New Contributors 135 | 136 | - @dependabot made their first contribution in https://github.com/salahhusa9/laravel-updater/pull/1 137 | - @salahhusa9 made their first contribution in https://github.com/salahhusa9/laravel-updater/pull/5 138 | - @renovate made their first contribution in https://github.com/salahhusa9/laravel-updater/pull/4 139 | 140 | **Full Changelog**: https://github.com/salahhusa9/laravel-updater/commits/v0.0.1 141 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) salahhusa9 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 13 | all 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 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Laravel Updater 2 | 3 | [![Latest Version on Packagist](https://img.shields.io/packagist/v/salahhusa9/laravel-updater.svg?style=flat-square)](https://packagist.org/packages/salahhusa9/laravel-updater) 4 | ![laravel](https://img.shields.io/badge/Laravel-10%7C11%7C12-red) 5 | [![GitHub Tests Action Status](https://img.shields.io/github/actions/workflow/status/salahhusa9/laravel-updater/run-tests.yml?branch=main&label=tests&style=flat-square)](https://github.com/salahhusa9/laravel-updater/actions?query=workflow%3Arun-tests+branch%3Amain) 6 | [![GitHub Code Style Action Status](https://img.shields.io/github/actions/workflow/status/salahhusa9/laravel-updater/fix-php-code-style-issues.yml?branch=main&label=code%20style&style=flat-square)](https://github.com/salahhusa9/laravel-updater/actions?query=workflow%3A"Fix+PHP+code+style+issues"+branch%3Amain) 7 | [![Total Downloads](https://img.shields.io/packagist/dt/salahhusa9/laravel-updater.svg?style=flat-square)](https://packagist.org/packages/salahhusa9/laravel-updater) 8 | 9 | This is a useful package for update your laravel project with one command/click. 10 | 11 | ## Support us 12 | 13 | You can support us by [buying me a coffee](https://github.com/sponsors/salahhusa9) ☕️ . 14 | 15 | 16 | 17 | ## Docs 18 | You find the **docs** in [salahhusa9.com/laravel-updater](https://salahhusa9.com/laravel-updater) 19 | 20 | ## Testing 21 | 22 | ```bash 23 | composer test 24 | ``` 25 | 26 | ## Changelog 27 | 28 | Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently. 29 | 30 | ## Contributing 31 | 32 | Please see [CONTRIBUTING](CONTRIBUTING.md) for details. 33 | 34 | ## Security Vulnerabilities 35 | 36 | Please review [our security policy](../../security/policy) on how to report security vulnerabilities. 37 | 38 | ## Credits 39 | 40 | - [salahhusa9](https://github.com/salahhusa9) 41 | - [All Contributors](../../contributors) 42 | 43 | ## License 44 | 45 | The MIT License (MIT). Please see [License File](LICENSE.md) for more information. 46 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "salahhusa9/laravel-updater", 3 | "description": "Laravel Updater is a simple yet powerful package for updater your Laravel applications. It makes it easy to upgrade your application to the latest version with just one command.", 4 | "keywords": [ 5 | "salahhusa9", 6 | "laravel", 7 | "laravel-updater", 8 | "laravel package", 9 | "laravel self updater", 10 | "laravel package self updater", 11 | "laravel package updater", 12 | "laravel package update", 13 | "laravel package update itself" 14 | ], 15 | "homepage": "https://github.com/salahhusa9/laravel-updater", 16 | "license": "MIT", 17 | "authors": [ 18 | { 19 | "name": "salahhusa9", 20 | "email": "salahhusa9@gmail.com", 21 | "role": "Developer" 22 | } 23 | ], 24 | "require": { 25 | "php": "^8.1|^8.2", 26 | "guzzlehttp/guzzle": "^7.8", 27 | "illuminate/contracts": "^10.0|^11.0|^12.0", 28 | "spatie/laravel-package-tools": "^1.0", 29 | "symfony/process": "^6.3|^7.0" 30 | }, 31 | "require-dev": { 32 | "laravel/pint": "^1.0", 33 | "nunomaduro/collision": "^7.8|^8.0", 34 | "orchestra/testbench": "10.1.0", 35 | "pestphp/pest": "^2.20|^3.0", 36 | "pestphp/pest-plugin-arch": "^2.0|^3.0", 37 | "pestphp/pest-plugin-laravel": "^2.0|^3.0" 38 | }, 39 | "autoload": { 40 | "psr-4": { 41 | "Salahhusa9\\Updater\\": "src/", 42 | "Salahhusa9\\Updater\\Database\\Factories\\": "database/factories/" 43 | } 44 | }, 45 | "autoload-dev": { 46 | "psr-4": { 47 | "Salahhusa9\\Updater\\Tests\\": "tests/", 48 | "Workbench\\App\\": "workbench/app/" 49 | } 50 | }, 51 | "scripts": { 52 | "post-autoload-dump": "@composer run prepare", 53 | "clear": "@php vendor/bin/testbench package:purge-laravel-updater --ansi", 54 | "prepare": "@php vendor/bin/testbench package:discover --ansi", 55 | "build": [ 56 | "@composer run prepare", 57 | "@php vendor/bin/testbench workbench:build --ansi" 58 | ], 59 | "start": [ 60 | "Composer\\Config::disableProcessTimeout", 61 | "@composer run build", 62 | "@php vendor/bin/testbench serve" 63 | ], 64 | "test": "vendor/bin/pest", 65 | "test-coverage": "vendor/bin/pest --coverage", 66 | "format": "vendor/bin/pint" 67 | }, 68 | "config": { 69 | "sort-packages": true, 70 | "allow-plugins": { 71 | "pestphp/pest-plugin": true 72 | } 73 | }, 74 | "extra": { 75 | "laravel": { 76 | "providers": [ 77 | "Salahhusa9\\Updater\\UpdaterServiceProvider" 78 | ], 79 | "aliases": { 80 | "Updater": "Salahhusa9\\Updater\\Facades\\Updater" 81 | } 82 | } 83 | }, 84 | "minimum-stability": "dev", 85 | "prefer-stable": true 86 | } 87 | -------------------------------------------------------------------------------- /config/updater.php: -------------------------------------------------------------------------------- 1 | 'git', 7 | 8 | 'repository_source' => \Salahhusa9\Updater\RepositorySource\GithubRepository::class, 9 | 'github_token' => env('GITHUB_TOKEN'), 10 | 'github_username' => env('GITHUB_USERNAME'), 11 | 'github_repository' => env('GITHUB_REPOSITORY'), 12 | 13 | 'github_timeout' => 100, 14 | 15 | 'maintenance_mode' => true, 16 | 'maintenance_mode_secret' => env('MAINTENANCE_MODE_SECRET', false), 17 | 18 | 'before_update_pipelines' => [ 19 | // you can add your own pipelines here 20 | ], 21 | 22 | // run php artisan migrate after update? 23 | 'migrate' => false, 24 | 25 | // run seeders after update? 26 | 'seeders' => [ 27 | // '\Database\Seeders\DatabaseSeeder::class', 28 | ], 29 | 30 | // run php artisan cache:clear after update? 31 | 'cache:clear' => false, 32 | 33 | // run php artisan view:clear after update? 34 | 'view:clear' => false, 35 | 36 | // run php artisan config:clear after update? 37 | 'config:clear' => false, 38 | 39 | // run php artisan route:clear after update? 40 | 'route:clear' => false, 41 | 42 | // run php artisan optimize after update? 43 | 'optimize' => false, 44 | 45 | 'after_update_pipelines' => [ 46 | // you can add your own pipelines here 47 | ], 48 | 49 | ]; 50 | -------------------------------------------------------------------------------- /database/factories/ModelFactory.php: -------------------------------------------------------------------------------- 1 | components->info('No new version available'); 20 | 21 | return self::SUCCESS; 22 | } 23 | 24 | $this->components->info('New version available: '.$newVersionAvailable['latest_version']); 25 | 26 | event(new NewVersionAvailable($newVersionAvailable['current_version'], $newVersionAvailable['latest_version'])); 27 | 28 | return self::SUCCESS; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Commands/UpdaterCommand.php: -------------------------------------------------------------------------------- 1 | components->error('No new version available'); 19 | 20 | return self::FAILURE; 21 | } 22 | 23 | $this->components->info('Updating to version '.$newVersionAvailable['latest_version']); 24 | 25 | Updater::update(output: function ($message) { 26 | $this->components->task($message); 27 | }); 28 | 29 | $this->components->twoColumnDetail('Application updated', Updater::getCurrentVersion()); 30 | 31 | $this->components->info(' 32 | Thank you for using this package! ❤️ 33 | Consider supporting my work: 34 | https://github.com/sponsors/salahhusa9 35 | '); 36 | 37 | return self::SUCCESS; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Contracts/Pipeline.php: -------------------------------------------------------------------------------- 1 | currentVersion = $currentVersion; 19 | $this->newVersion = $newVersion; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Events/UpdateFailed.php: -------------------------------------------------------------------------------- 1 | pastVersion = $pastVersion; 21 | $this->newVersion = $newVersion; 22 | $this->exception = $exception; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Events/UpdatedSuccessfully.php: -------------------------------------------------------------------------------- 1 | pastVersion = $pastVersion; 19 | $this->newVersion = $newVersion; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Exceptions/GitFailedException.php: -------------------------------------------------------------------------------- 1 | failed()) { 22 | throw new GitFailedException('this command failed: '.$process->command().' with message: '.$process->errorOutput()); 23 | } 24 | 25 | return trim($process->output()); 26 | } 27 | 28 | /** 29 | * getCurrentBranch 30 | * 31 | * @return string 32 | * 33 | * @throws GitFailedException 34 | */ 35 | public static function getCurrentBranch() 36 | { 37 | $process = Process::run(self::gitPath().' rev-parse --abbrev-ref HEAD'); 38 | 39 | if ($process->failed()) { 40 | throw new GitFailedException('this command failed: '.$process->command().' with message: '.$process->errorOutput()); 41 | } 42 | 43 | return trim($process->output()); 44 | } 45 | 46 | /** 47 | * getCurrentTag 48 | * 49 | * @return string 50 | * 51 | * @throws GitFailedException 52 | */ 53 | public static function getCurrentTag() 54 | { 55 | $process = Process::run(self::gitPath().' describe --tags --abbrev=0'); 56 | 57 | if ($process->failed()) { 58 | throw new GitFailedException('this command failed: '.$process->command().' with message: '.$process->errorOutput()); 59 | } 60 | 61 | return trim($process->output()); 62 | } 63 | 64 | /** 65 | * auth 66 | * 67 | * @return string 68 | * 69 | * @throws GitFailedException 70 | */ 71 | public static function auth() 72 | { 73 | $process = Process::run(self::gitPath().' remote set-url origin https://'.config('updater.github_username').':'.config('updater.github_token').'@github.com/'.config('updater.github_username').'/'.config('updater.github_repository').'.git'); 74 | 75 | if ($process->failed()) { 76 | throw new GitFailedException('this command failed: '.$process->command().' with message: '.$process->errorOutput()); 77 | } 78 | 79 | return trim($process->output()); 80 | } 81 | 82 | /** 83 | * pull 84 | * 85 | * @return string 86 | * 87 | * @throws GitFailedException 88 | */ 89 | public static function pull() 90 | { 91 | $process = Process::run(self::gitPath().' pull'); 92 | 93 | if ($process->failed()) { 94 | throw new GitFailedException('this command failed: '.$process->command().' with message: '.$process->errorOutput()); 95 | } 96 | 97 | return trim($process->output()); 98 | } 99 | 100 | /** 101 | * checkout 102 | * 103 | * @param mixed $branch 104 | * @return string 105 | * 106 | * @throws GitFailedException 107 | */ 108 | public static function checkout($branch) 109 | { 110 | $process = Process::run(self::gitPath().' checkout '.$branch.' -f'); 111 | 112 | if ($process->failed()) { 113 | throw new GitFailedException('this command failed: '.$process->command().' with message: '.$process->errorOutput()); 114 | } 115 | 116 | return trim($process->output()); 117 | } 118 | 119 | /** 120 | * fetch 121 | * 122 | * @return string 123 | * 124 | * @throws GitFailedException 125 | */ 126 | public static function fetch() 127 | { 128 | $process = Process::run(self::gitPath().' fetch'); 129 | 130 | if ($process->failed()) { 131 | throw new GitFailedException('this command failed: '.$process->command().' with message: '.$process->errorOutput()); 132 | } 133 | 134 | return trim($process->output()); 135 | } 136 | 137 | /** 138 | * gitPath 139 | * 140 | * @return string 141 | */ 142 | public static function gitPath() 143 | { 144 | $gitPath = config('updater.git_path', 'git'); 145 | 146 | return $gitPath; 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /src/Helpers/Helper.php: -------------------------------------------------------------------------------- 1 | true, 26 | ]); 27 | 28 | if (is_callable($content['output'])) { 29 | call_user_func($content['output'], 'Migrated!'); 30 | } 31 | 32 | return $next($content); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Pipelines/ArtisanCallOptimizePipe.php: -------------------------------------------------------------------------------- 1 | $class, 29 | '--force' => true, 30 | ]); 31 | } 32 | 33 | if (is_callable($content['output'])) { 34 | call_user_func($content['output'], 'Seeded!'); 35 | } 36 | 37 | return $next($content); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/RepositorySource/GithubRepository.php: -------------------------------------------------------------------------------- 1 | checkConfig(); 17 | 18 | return isset($this->getLatestVersionData()['message']) ? throw new \Exception($this->getLatestVersionData()['message']) : $this->getLatestVersionData()['tag_name']; 19 | } 20 | 21 | /** 22 | * getLatestVersionData 23 | * 24 | * @return Illuminate\Support\Collection 25 | */ 26 | public function getLatestVersionData(): \Illuminate\Support\Collection 27 | { 28 | $this->checkConfig(); 29 | 30 | $response = Http::withHeaders([ 31 | 'Accept' => 'application/vnd.github.v3+json', 32 | 'Authorization' => 'Bearer '.config('updater.github_token'), 33 | 'X-GitHub-Api-Version' => '2022-11-28', 34 | ]) 35 | ->timeout(config('updater.github_timeout', 100)) 36 | ->get('https://api.github.com/repos/'.config('updater.github_username').'/'.config('updater.github_repository').'/releases/latest'); 37 | 38 | return $response->collect(); 39 | } 40 | 41 | /** 42 | * getVersions 43 | */ 44 | public function getVersions(): array 45 | { 46 | $this->checkConfig(); 47 | 48 | $versionsData = $this->getVersionsData(); 49 | 50 | if (isset($versionsData['message'])) { 51 | throw new \Exception($versionsData['message']); 52 | } 53 | 54 | return $versionsData->map(function ($version) { 55 | return $version['tag_name']; 56 | })->toArray(); 57 | } 58 | 59 | /** 60 | * getVersionsData 61 | * 62 | * @return Illuminate\Support\Collection 63 | */ 64 | public function getVersionsData(): \Illuminate\Support\Collection 65 | { 66 | $this->checkConfig(); 67 | 68 | $response = Http::withHeaders([ 69 | 'Accept' => 'application/vnd.github.v3+json', 70 | 'Authorization' => 'Bearer '.config('updater.github_token'), 71 | 'X-GitHub-Api-Version' => '2022-11-28', 72 | ]) 73 | ->timeout(config('updater.github_timeout', 100)) 74 | ->get('https://api.github.com/repos/'.config('updater.github_username').'/'.config('updater.github_repository').'/releases'); 75 | 76 | return $response->collect(); 77 | } 78 | 79 | /** 80 | * checkConfig 81 | * 82 | * @return void 83 | */ 84 | public function checkConfig() 85 | { 86 | if (config('updater.github_token') == null) { 87 | throw new GithubConfigException('Please set GITHUB_TOKEN in .env file'); 88 | } 89 | 90 | if (config('updater.github_username') == null) { 91 | throw new GithubConfigException('Please set GITHUB_USERNAME in .env file'); 92 | } 93 | 94 | if (config('updater.github_repository') == null) { 95 | throw new GithubConfigException('Please set GITHUB_REPOSITORY in .env file'); 96 | } 97 | 98 | return true; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/Updater.php: -------------------------------------------------------------------------------- 1 | output = $output; 25 | 26 | if (is_array($this->newVersionAvailable())) { 27 | return $this->updateTo($this->getLatestVersion()); 28 | } else { 29 | return 'No new version available'; 30 | } 31 | } 32 | 33 | /** 34 | * updateTo 35 | * 36 | * @param mixed $version 37 | */ 38 | private function updateTo($version): string 39 | { 40 | if (is_array($this->newVersionAvailable()) && $this->newVersionAvailable()['current_version'] != $version) { 41 | 42 | $current_version_in_past = $this->newVersionAvailable()['current_version']; 43 | 44 | try { 45 | if (config('updater.maintenance_mode', false)) { 46 | $this->output('Maintenance mode is on, turning it on'); 47 | 48 | Artisan::call( 49 | 'down', 50 | config('updater.maintenance_mode_secret', false) ? [ 51 | '--secret' => config('updater.maintenance_mode_secret', false), 52 | ] : [] 53 | ); 54 | } 55 | 56 | $pipelines = [ 57 | Pipelines\GitPipe::class, 58 | ]; 59 | 60 | if (config('updater.before_update_pipelines', false) && is_array(config('updater.before_update_pipelines')) && count(config('updater.before_update_pipelines')) > 0) { 61 | $pipelines = array_merge($pipelines, config('updater.before_update_pipelines')); 62 | } 63 | 64 | if (config('updater.migrate', false)) { 65 | $pipelines[] = Pipelines\ArtisanCallMigratePipe::class; 66 | } 67 | 68 | if (config('updater.seeders', false) && is_array(config('updater.seeders')) && count(config('updater.seeders')) > 0) { 69 | $pipelines[] = Pipelines\SeedersPipe::class; 70 | } 71 | 72 | if (config('updater.cache:clear', false)) { 73 | $pipelines[] = Pipelines\ArtisanCallCacheClearPipe::class; 74 | } 75 | 76 | if (config('updater.view:clear', false)) { 77 | $pipelines[] = Pipelines\ArtisanCallViewClearPipe::class; 78 | } 79 | 80 | if (config('updater.config:clear', false)) { 81 | $pipelines[] = Pipelines\ArtisanCallConfigClearPipe::class; 82 | } 83 | 84 | if (config('updater.route:clear', false)) { 85 | $pipelines[] = Pipelines\ArtisanCallRouteClearPipe::class; 86 | } 87 | 88 | if (config('updater.optimize', false)) { 89 | $pipelines[] = Pipelines\ArtisanCallOptimizePipe::class; 90 | } 91 | 92 | if (config('updater.after_update_pipelines', false) && is_array(config('updater.after_update_pipelines')) && count(config('updater.after_update_pipelines')) > 0) { 93 | $pipelines = array_merge($pipelines, config('updater.after_update_pipelines')); 94 | } 95 | 96 | // check if pipelines is array and not empty and items is implemented Pipeline contract 97 | if (is_array($pipelines) && count($pipelines) > 0) { 98 | foreach ($pipelines as $pipeline) { 99 | if (! is_subclass_of($pipeline, \Salahhusa9\Updater\Contracts\Pipeline::class)) { 100 | throw new \RuntimeException('Pipeline '.$pipeline.' is not implemented Pipeline contract:'.\Salahhusa9\Updater\Contracts\Pipeline::class); 101 | } 102 | } 103 | } else { 104 | throw new \RuntimeException('Pipelines is not array or empty'); 105 | } 106 | 107 | $this->output('Start Updating to version '.$version); 108 | 109 | Pipeline::send([ 110 | 'current_version' => $this->getCurrentVersion(), 111 | 'new_version' => $version, 112 | 'output' => $this->output, 113 | ]) 114 | ->through($pipelines) 115 | ->then( 116 | function ($content) { 117 | return $content; 118 | } 119 | ); 120 | 121 | if (config('updater.maintenance_mode', false)) { 122 | $this->output('Maintenance mode is on, turning it off'); 123 | Artisan::call('up'); 124 | } 125 | 126 | event(new Events\UpdatedSuccessfully($current_version_in_past, $version)); 127 | 128 | return 'Updated to version '.$version; 129 | } catch (\Throwable $th) { 130 | if (config('updater.maintenance_mode', false)) { 131 | $this->output('Maintenance mode is on, turning it off'); 132 | Artisan::call('up'); 133 | } 134 | 135 | event(new Events\UpdateFailed($current_version_in_past, $version, $th->getMessage())); 136 | 137 | throw $th; 138 | } 139 | } else { 140 | $this->output('No new version available'); 141 | 142 | return 'No new version available'; 143 | } 144 | } 145 | 146 | /** 147 | * output 148 | * 149 | * @param mixed $message 150 | */ 151 | public function output($message): void 152 | { 153 | if (is_callable($this->output)) { 154 | call_user_func($this->output, $message); 155 | } 156 | } 157 | 158 | /** 159 | * newVersionAvailable 160 | * 161 | * @return bool 162 | */ 163 | public function newVersionAvailable(): bool|array 164 | { 165 | $currentVersion = $this->getCurrentVersion(); 166 | $latestVersion = $this->getLatestVersion(); 167 | 168 | if ($currentVersion != $latestVersion) { 169 | return [ 170 | 'current_version' => $currentVersion, 171 | 'latest_version' => $latestVersion, 172 | ]; 173 | } 174 | 175 | return false; 176 | } 177 | 178 | /** 179 | * getCurrentVersion 180 | */ 181 | public function getCurrentVersion(): string 182 | { 183 | $branch = Git::getCurrentBranch(); 184 | $tag = Git::getCurrentTag(); 185 | 186 | $head = $branch != 'HEAD' ? $branch : $tag; 187 | 188 | return $head; 189 | } 190 | 191 | /** 192 | * getLatestVersion 193 | */ 194 | public function getLatestVersion(): string 195 | { 196 | return Cache::remember('latest_version', 5, function () { 197 | return app(Repository::class)->getLatestVersion(); 198 | }); 199 | } 200 | 201 | /** 202 | * getLatestVersionData 203 | */ 204 | public function getLatestVersionData(): array 205 | { 206 | return Cache::remember('latest_version_data', 5, function () { 207 | return app(Repository::class)->getLatestVersionData()->toArray(); 208 | }); 209 | } 210 | 211 | /** 212 | * versions 213 | */ 214 | public function versions(): array 215 | { 216 | return Cache::remember('versions', 5, function () { 217 | return app(Repository::class)->getVersions(); 218 | }); 219 | } 220 | } 221 | -------------------------------------------------------------------------------- /src/UpdaterServiceProvider.php: -------------------------------------------------------------------------------- 1 | name('laravel-updater') 23 | ->hasConfigFile() 24 | ->hasViews() 25 | ->hasCommands(UpdaterCommand::class, CheckCommand::class); 26 | 27 | $this->app->singleton(Repository::class, function () { 28 | return new (config('updater.repository_source', GithubRepository::class))(); 29 | }); 30 | } 31 | } 32 | --------------------------------------------------------------------------------