diff --git a/app/Console/Commands/PerformUpdate.php b/app/Console/Commands/PerformUpdate.php index 59b7b95..d466417 100644 --- a/app/Console/Commands/PerformUpdate.php +++ b/app/Console/Commands/PerformUpdate.php @@ -35,6 +35,12 @@ public function handle(): int /** @var Site $site */ $site = Site::findOrFail($this->input->getArgument('siteId')); + if (!$site->update_requirement_state) { + $this->output->writeln('Update requirements not met, aborting!'); + + return Command::FAILURE; + } + UpdateSite::dispatchSync( $site, $targetVersion diff --git a/app/Console/Commands/QueueUpdates.php b/app/Console/Commands/QueueUpdates.php index 57b433d..60360f2 100644 --- a/app/Console/Commands/QueueUpdates.php +++ b/app/Console/Commands/QueueUpdates.php @@ -39,6 +39,7 @@ public function handle(): int $this->output->writeln('Pushing update jobs'); $sites = Site::query() + ->where('update_requirement_state', '=', true) ->where( 'cms_version', 'like', diff --git a/app/Jobs/CheckSiteHealth.php b/app/Jobs/CheckSiteHealth.php index 0c7e5ab..8fc188e 100644 --- a/app/Jobs/CheckSiteHealth.php +++ b/app/Jobs/CheckSiteHealth.php @@ -42,6 +42,11 @@ public function handle(): void $this->site->last_seen = Carbon::now(); $this->site->save(); + // Check if conditions are met + if (!$this->site->update_requirement_state) { + return; + } + // Check if a newer Joomla version for that site is available /** @var TufFetcher $tufFetcher */ $tufFetcher = App::make(TufFetcher::class); diff --git a/app/Jobs/UpdateSite.php b/app/Jobs/UpdateSite.php index 11ae42e..9b9b4a0 100644 --- a/app/Jobs/UpdateSite.php +++ b/app/Jobs/UpdateSite.php @@ -51,6 +51,12 @@ public function handle(): void return; } + if (!$healthResult->update_requirement_state) { + Log::info("Site does not meet requirements, abort"); + + return; + } + // Do not make a major version update $majorVersionCms = (int) $healthResult->cms_version; $majorTargetVersion = (int) $this->targetVersion; diff --git a/app/Models/Site.php b/app/Models/Site.php index 66a4fcf..ae3b91e 100644 --- a/app/Models/Site.php +++ b/app/Models/Site.php @@ -20,9 +20,7 @@ class Site extends Model 'db_version', 'cms_version', 'server_os', - 'update_patch', - 'update_minor', - 'update_major' + 'update_requirement_state' ]; protected $hidden = [ @@ -33,9 +31,7 @@ protected function casts(): array { return [ 'last_seen' => 'datetime', - 'update_patch' => 'bool', - 'update_minor' => 'bool', - 'update_major' => 'bool' + 'update_requirement_state' => 'bool', ]; } diff --git a/app/RemoteSite/Responses/HealthCheck.php b/app/RemoteSite/Responses/HealthCheck.php index 1af735a..ba6d4ee 100644 --- a/app/RemoteSite/Responses/HealthCheck.php +++ b/app/RemoteSite/Responses/HealthCheck.php @@ -11,7 +11,8 @@ public function __construct( public string $db_type, public string $db_version, public string $cms_version, - public string $server_os + public string $server_os, + public ?bool $update_requirement_state = null ) { } } diff --git a/database/migrations/2025_05_18_143851_add_update_requirement_state_to_sites_table.php b/database/migrations/2025_05_18_143851_add_update_requirement_state_to_sites_table.php new file mode 100644 index 0000000..87e0d02 --- /dev/null +++ b/database/migrations/2025_05_18_143851_add_update_requirement_state_to_sites_table.php @@ -0,0 +1,27 @@ +boolean('update_requirement_state')->default(false)->nullable(true); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('sites', function (Blueprint $table) { + $table->dropColumn('update_requirement_state'); + }); + } +}; diff --git a/tests/Feature/Api/SiteControllerTest.php b/tests/Feature/Api/SiteControllerTest.php index e44115a..3a6efd9 100644 --- a/tests/Feature/Api/SiteControllerTest.php +++ b/tests/Feature/Api/SiteControllerTest.php @@ -37,7 +37,8 @@ public function testRegisteringASiteWithUrlAndKeyCreatesRow(): void "db_type" => "mysqli", "db_version" => "1.0.0", "cms_version" => "1.0.0", - "server_os" => "Joomla OS 1.0.0" + "server_os" => "Joomla OS 1.0.0", + "update_requirement_state" => true ])); $this->app->bind(Connection::class, fn () => $mock); @@ -170,7 +171,8 @@ protected function createMockSiteInDb(): Site "db_version" => "1.0.0", "cms_version" => "1.0.0", "server_os" => "Joomla OS 1.0.0", - "last_seen" => Carbon::now() + "last_seen" => Carbon::now(), + "update_requirement_state" => true ]); $site->key = 'foobar123foobar123foobar123foobar123'; diff --git a/tests/Unit/Jobs/CheckSiteHealthTest.php b/tests/Unit/Jobs/CheckSiteHealthTest.php index 0e42e40..02be82a 100644 --- a/tests/Unit/Jobs/CheckSiteHealthTest.php +++ b/tests/Unit/Jobs/CheckSiteHealthTest.php @@ -84,6 +84,7 @@ function () use ($healthMock) { $siteMock->id = 1; $siteMock->url = "http://example.org"; $siteMock->cms_version = "1.0.0"; + $siteMock->update_requirement_state = true; return $siteMock; } @@ -95,7 +96,8 @@ protected function getHealthCheckMock($overrides = []) "db_type" => "mysqli", "db_version" => "1.0.0", "cms_version" => "1.0.0", - "server_os" => "Joomla OS 1.0.0" + "server_os" => "Joomla OS 1.0.0", + "update_requirement_state" => true ]; return HealthCheck::from([ diff --git a/tests/Unit/Jobs/UpdateSiteTest.php b/tests/Unit/Jobs/UpdateSiteTest.php index 569df9a..f4a1c51 100644 --- a/tests/Unit/Jobs/UpdateSiteTest.php +++ b/tests/Unit/Jobs/UpdateSiteTest.php @@ -59,6 +59,28 @@ public function testJobQuitsIfNoUpdateIsAvailable() $this->assertTrue(true); } + public function testJobQuitsIfRequirementsArentMet() + { + $site = $this->getSiteMock( + [ + 'checkHealth' => $this->getHealthCheckMock(['update_requirement_state' => false]) + ] + ); + + Log::spy(); + + $object = new UpdateSite($site, "1.0.1"); + $object->handle(); + + Log::shouldHaveReceived('info') + ->once() + ->withArgs(function ($message) { + return str_contains($message, 'Site does not meet requirements, abort'); + }); + + $this->assertTrue(true); + } + public function testJobQuitsIfWeDetectALoopForAVersion() { $site = $this->getSiteMock([], null, 6); @@ -241,7 +263,8 @@ protected function getHealthCheckMock($overrides = []) "db_type" => "mysqli", "db_version" => "1.0.0", "cms_version" => "1.0.0", - "server_os" => "Joomla OS 1.0.0" + "server_os" => "Joomla OS 1.0.0", + "update_requirement_state" => true ]; return HealthCheck::from([