Skip to content

chore/package-update #6

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Mar 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,16 @@ jobs:
# not self-hosted, because it's a public repo
runs-on: ubuntu-latest

# we want to run it on combination of PHP 8.1+ and Laravel 9.1+
# we want to run it on combination of PHP and Laravel versions
strategy:
fail-fast: false
matrix:
php: ['8.2', '8.3']
laravel: ['^10.0', '^11.0']
php: ['8.2', '8.3', '8.4']
laravel: ['^10.0', '^11.0', '^12.0']

steps:
- name: Checkout the repo
uses: actions/checkout@v2
uses: actions/checkout@v3

- name: Setup PHP
uses: shivammathur/setup-php@v2
Expand Down
15 changes: 8 additions & 7 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@
],
"require": {
"php": "^8.2",
"illuminate/contracts": "^10.0|^11.0",
"illuminate/console": "^10.0|^11.0",
"illuminate/database": "^10.0|^11.0",
"illuminate/support": "^10.0|^11.0"
"illuminate/contracts": "^10.0 | ^11.0 | ^12.0",
"illuminate/console": "^10.0 | ^11.0 | ^12.0",
"illuminate/database": "^10.0 | ^11.0 | ^12.0",
"illuminate/support": "^10.0 | ^11.0 | ^12.0"
},
"require-dev": {
"orchestra/testbench": "^8.0|^9.0",
"spatie/fork": "^1.1"
"orchestra/testbench": "^8.0 | ^9.0 | ^10.0",
"spatie/fork": "^1.2"
},
"autoload": {
"psr-4": {
Expand All @@ -43,7 +43,8 @@
"extra": {
"laravel": {
"providers": [
"Netsells\\LaravelMutexMigrations\\ServiceProvider"
"Netsells\\LaravelMutexMigrations\\DependencyBindingProvider",
"Netsells\\LaravelMutexMigrations\\PackageProvider"
]
}
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<?php

namespace Netsells\LaravelMutexMigrations;
declare(strict_types=1);

namespace Netsells\LaravelMutexMigrations\Commands;

use Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Database\Console\Migrations\MigrateCommand;
Expand All @@ -15,25 +17,39 @@ public function __construct(Migrator $migrator, Dispatcher $dispatcher)
parent::__construct($migrator, $dispatcher);

parent::addOption(...MutexMigrateCommand::getMutexOption());
parent::addOption(...MutexMigrateCommand::getMutexGracefulOption());
}

public function handle(): int
{
if ($this->option(MutexMigrateCommand::OPTION_MUTEX)) {
if ($this->shouldUseMutex()) {
try {
return $this->call(MutexMigrateCommand::class, $this->getCommandOptions());
} catch (DatabaseCacheTableNotFoundException $e) {
$this->components->warn('Falling back to a standard migration');
if ($this->option(MutexMigrateCommand::OPTION_MUTEX)) {
return $this->options('graceful') ? self::SUCCESS : self::FAILURE;
} elseif ($this->option(MutexMigrateCommand::OPTION_MUTEX_GRACEFUL)) {
$this->components->warn('Falling back to a standard migration');
}
}
}

return parent::handle();
}

private function shouldUseMutex(): bool
{
return $this->option(MutexMigrateCommand::OPTION_MUTEX)
|| $this->option(MutexMigrateCommand::OPTION_MUTEX_GRACEFUL);
}

private function getCommandOptions(): array
{
return Collection::make($this->options())
->reject(fn ($value, $key) => $key === MutexMigrateCommand::OPTION_MUTEX)
->reject(fn ($value, $key) => \in_array($key, [
MutexMigrateCommand::OPTION_MUTEX,
MutexMigrateCommand::OPTION_MUTEX_GRACEFUL,
]))
->mapWithKeys(fn ($value, $key) => ["--$key" => $value])
->all();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<?php

namespace Netsells\LaravelMutexMigrations;
declare(strict_types=1);

namespace Netsells\LaravelMutexMigrations\Commands;

use Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Database\Console\Migrations\MigrateCommand;
Expand All @@ -14,13 +16,20 @@ class MutexMigrateCommand extends MigrateCommand
{
public const OPTION_MUTEX = 'mutex';

public const OPTION_MUTEX_GRACEFUL = 'mutex-graceful';

private MigrationProcessorInterface $processor;

public static function getMutexOption(): array
{
return [self::OPTION_MUTEX, null, InputOption::VALUE_NONE, 'Run a mutually exclusive migration'];
}

public static function getMutexGracefulOption(): array
{
return [self::OPTION_MUTEX_GRACEFUL, null, InputOption::VALUE_NONE, 'Run a mutually exclusive migration and gracefully failover to a standard migration if the application does not contain the required lock table'];
}

public function __construct(
Migrator $migrator,
Dispatcher $dispatcher,
Expand Down
65 changes: 65 additions & 0 deletions src/DependencyBindingProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?php

declare(strict_types=1);

namespace Netsells\LaravelMutexMigrations;

use Illuminate\Contracts\Support\DeferrableProvider;
use Illuminate\Database\Console\Migrations\MigrateCommand;
use Illuminate\Database\Migrations\Migrator;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\ServiceProvider as BaseServiceProvider;
use Netsells\LaravelMutexMigrations\Commands;
use Netsells\LaravelMutexMigrations\Mutex;

class DependencyBindingProvider extends BaseServiceProvider implements DeferrableProvider
{
/**
* Get the services provided by the provider.
*
* @return list<class-string>
*/
public function provides(): array
{
return [
MigrateCommand::class,
Commands\MutexMigrateCommand::class,
Mutex\MutexRelay::class,
];
}

/**
* Register any application services.
*/
public function register(): void
{
$this->app->bind(MigrateCommand::class, Commands\MigrateCommandExtension::class);

$this->app->when([Commands\MigrateCommandExtension::class, Commands\MutexMigrateCommand::class])
->needs(Migrator::class)
->give(function ($app) {
return $app['migrator'];
});

$this->app->bind(Mutex\MutexRelay::class, function ($app) {
$store = Config::get('mutex-migrations.lock.store');

return new Mutex\MutexRelay(
cache: Cache::store($store),
lockDurationSeconds: Config::get('mutex-migrations.lock.ttl_seconds')
?? Mutex\MutexRelay::DEFAULT_TTL_SECONDS,
lockTable: Config::get("cache.stores.{$store}.lock_table")
?? Mutex\MutexRelay::DEFAULT_LOCK_TABLE,
);
});
}

/**
* Bootstrap any package services.
*/
public function boot(): void
{
//
}
}
2 changes: 2 additions & 0 deletions src/Mutex/DatabaseCacheTableNotFoundException.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

namespace Netsells\LaravelMutexMigrations\Mutex;

class DatabaseCacheTableNotFoundException extends \Exception
Expand Down
11 changes: 9 additions & 2 deletions src/Mutex/MutexRelay.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

namespace Netsells\LaravelMutexMigrations\Mutex;

use Illuminate\Contracts\Cache\Lock;
Expand All @@ -11,13 +13,15 @@ class MutexRelay implements MutexRelayInterface
{
public const DEFAULT_LOCK_TABLE = 'cache_locks';

public const DEFAULT_TTL_SECONDS = 60;

public const KEY = 'laravel-mutex-migrations';

private ?Lock $lock = null;

public function __construct(
private readonly Repository $cache,
private readonly int $lockDurationSeconds = 60,
private readonly int $lockDurationSeconds = self::DEFAULT_TTL_SECONDS,
private readonly string $lockTable = self::DEFAULT_LOCK_TABLE,
) {
//
Expand Down Expand Up @@ -59,6 +63,9 @@ private function isCacheTableNotFoundException(\Throwable $th): bool
return false;
}

return $th->getCode() === '42S02' && Str::contains($th->getMessage(), $this->lockTable);
return Str::contains($th->getMessage(), $this->lockTable) && \in_array($th->getCode(), [
'42S02', // mysql
'HY000', // sqlite
], true);
}
}
2 changes: 2 additions & 0 deletions src/Mutex/MutexRelayInterface.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

namespace Netsells\LaravelMutexMigrations\Mutex;

interface MutexRelayInterface
Expand Down
2 changes: 2 additions & 0 deletions src/Mutex/NullRelay.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

namespace Netsells\LaravelMutexMigrations\Mutex;

class NullRelay implements MutexRelayInterface
Expand Down
36 changes: 36 additions & 0 deletions src/PackageProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

declare(strict_types=1);

namespace Netsells\LaravelMutexMigrations;

use Illuminate\Support\ServiceProvider as BaseServiceProvider;

class PackageProvider extends BaseServiceProvider
{
/**
* Register any application services.
*/
public function register(): void
{
if (! $this->app->runningInConsole()) {
return;
}

$this->mergeConfigFrom(__DIR__.'/../config/mutex-migrations.php', 'mutex-migrations');
}

/**
* Bootstrap any package services.
*/
public function boot(): void
{
if (! $this->app->runningInConsole()) {
return;
}

$this->publishes([
__DIR__.'/../config/mutex-migrations.php' => config_path('mutex-migrations.php'),
], 'mutex-migrations-config');
}
}
2 changes: 2 additions & 0 deletions src/Processors/MigrationProcessorFactory.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

namespace Netsells\LaravelMutexMigrations\Processors;

use Illuminate\Console\View\Components\Factory;
Expand Down
2 changes: 2 additions & 0 deletions src/Processors/MigrationProcessorInterface.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

namespace Netsells\LaravelMutexMigrations\Processors;

interface MigrationProcessorInterface
Expand Down
2 changes: 2 additions & 0 deletions src/Processors/MutexMigrationProcessor.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

namespace Netsells\LaravelMutexMigrations\Processors;

use Illuminate\Console\View\Components\Factory;
Expand Down
Loading