wishborn / upgrades
A system to manage data/code upgrades during deployments, similar to database migrations
Requires
- php: ^8.1
- illuminate/console: ^9.0|^10.0
- illuminate/database: ^9.0|^10.0
- illuminate/support: ^9.0|^10.0
- laravel/framework: ^9.0|^10.0
Requires (Dev)
- orchestra/testbench: ^8.0|^9.0
- pestphp/pest: ^2.0
- pestphp/pest-plugin-laravel: ^2.0
- phpunit/phpunit: ^10.0
README
A system to manage data/code upgrades during deployments, similar to database migrations.
Installation
You can install the package via composer:
composer require wishborn/upgrades
The package will automatically register its service provider.
After installation, you should run the migrations to create the required database table:
php artisan migrate
If the migration doesn't run automatically, you can force publish and run it:
# Publish the migrations php artisan vendor:publish --tag=wishborn-upgrades-migrations # Run migrations php artisan migrate
Usage
Creating an Upgrade
# Using the main command php artisan wish:make-upgrade "Add user settings" # Or using the Laravel-style alias php artisan make:wish "Add user settings"
This will create a new upgrade file in the upgrades
directory with a timestamp prefix.
Running Upgrades
To run all pending upgrades:
php artisan wish:run-upgrade
To skip confirmations:
php artisan wish:run-upgrade -y
Checking Status
To see the status of all upgrades:
php artisan wish:upgrade-status
Writing Upgrades
Upgrades are similar to Laravel migrations but for any type of data or code changes. All upgrades are automatically wrapped in a database transaction - if any part of the upgrade fails, all changes will be rolled back.
Here's an example:
<?php namespace Wishborn\Upgrades; use Wishborn\Upgrades\Support\Upgrade; use App\Models\User; class AddDefaultSettingsToUsers extends Upgrade { protected function up(): void { $this->info('Adding default settings to users...'); // If any part of this fails, all changes will be rolled back automatically User::whereNull('settings') ->chunk(100, function ($users) { foreach ($users as $user) { $this->line("Processing user: {$user->email}"); if ($this->confirm("Update user {$user->email}?")) { $user->settings = ['theme' => 'light']; $user->save(); } } }); $this->info('Default settings added successfully!'); } }
Available Methods
Output Methods:
$this->info('Message')
- Green text$this->error('Message')
- Red text$this->warn('Message')
- Yellow text$this->comment('Message')
- Yellow text$this->line('Message')
- Plain text$this->newLine(1)
- Add blank lines
Confirmations (skipped with -y flag):
if ($this->confirm('Continue?')) { // User confirmed }
Best Practices
- Make upgrades atomic and idempotent
- Transactions are handled automatically - all changes in an upgrade will be rolled back if any part fails
- Add descriptive comments and logging
- Handle errors gracefully
- Use chunking for large data operations
- Add confirmations for destructive operations
License
The MIT License (MIT). Please see License File for more information.
Testing
Package Development Testing
You can run tests using either PHPUnit or Pest:
# Using PHPUnit composer test composer test-coverage # Using Pest composer test:pest composer test:pest-coverage
Testing in Your Project
When using this package in your project, you can test your upgrades using either PHPUnit or Pest:
Using PHPUnit
use Tests\TestCase; use Wishborn\Upgrades\Models\Upgrade; class TestUpgradeTest extends TestCase { /** @test */ public function it_can_run_the_upgrade() { $this->artisan('make:wish', ['name' => 'TestUpgrade']); $this->artisan('upgrade:run') ->expectsOutput('Running upgrades...') ->assertExitCode(0); // Assert your upgrade changes here $this->assertTrue(true); } }
Using Pest
use Wishborn\Upgrades\Models\Upgrade; test('upgrade can be run successfully', function () { $this->artisan('make:wish', ['name' => 'TestUpgrade']); $this->artisan('upgrade:run') ->expectsOutput('Running upgrades...') ->assertExitCode(0); // Assert your upgrade changes here expect(true)->toBeTrue(); });
To run your tests:
# Using PHPUnit php artisan test # Using Pest ./vendor/bin/pest