From 67883ea8ff119f7573b31f460f6158014da51346 Mon Sep 17 00:00:00 2001 From: Simon Hamp Date: Sun, 19 Jul 2026 02:45:56 +0100 Subject: [PATCH] fix: update plugin name from composer.json on sync The name-sync guard only set the name when a plugin had none yet, so webhook (push/release) and admin re-syncs never picked up a renamed package. Update the name whenever composer.json's name differs, keeping the uniqueness guard and ignoring blank names. Co-Authored-By: Claude Opus 4.8 (1M context) --- app/Services/PluginSyncService.php | 2 +- tests/Feature/PluginSyncServiceTest.php | 89 +++++++++++++++++++++++++ 2 files changed, 90 insertions(+), 1 deletion(-) diff --git a/app/Services/PluginSyncService.php b/app/Services/PluginSyncService.php index ed38ed19..ccb836aa 100644 --- a/app/Services/PluginSyncService.php +++ b/app/Services/PluginSyncService.php @@ -65,7 +65,7 @@ public function sync(Plugin $plugin): bool ]; if ($composerData) { - if (isset($composerData['name']) && ! $plugin->name) { + if (! empty($composerData['name']) && $composerData['name'] !== $plugin->name) { $existing = Plugin::where('name', $composerData['name']) ->where('id', '!=', $plugin->id) ->exists(); diff --git a/tests/Feature/PluginSyncServiceTest.php b/tests/Feature/PluginSyncServiceTest.php index 01194736..c63e949d 100644 --- a/tests/Feature/PluginSyncServiceTest.php +++ b/tests/Feature/PluginSyncServiceTest.php @@ -53,6 +53,95 @@ public function test_sync_extracts_mobile_min_version_from_composer_data(): void $this->assertEquals('^3.0.0', $plugin->fresh()->mobile_min_version); } + public function test_sync_updates_name_from_composer_when_name_changes(): void + { + $composerJson = json_encode([ + 'name' => 'acme/renamed-plugin', + ]); + + Http::fake([ + 'api.github.com/repos/acme/test-plugin/contents/composer.json' => Http::response([ + 'content' => base64_encode($composerJson), + ]), + 'api.github.com/repos/acme/test-plugin/contents/nativephp.json' => Http::response([], 404), + 'raw.githubusercontent.com/*' => Http::response('', 404), + 'api.github.com/repos/acme/test-plugin/releases/latest' => Http::response([], 404), + 'api.github.com/repos/acme/test-plugin/tags*' => Http::response([]), + 'api.github.com/repos/acme/test-plugin/contents/LICENSE*' => Http::response([], 404), + ]); + + $plugin = Plugin::factory()->create([ + 'name' => 'acme/old-name', + 'repository_url' => 'https://github.com/acme/test-plugin', + ]); + + $service = new PluginSyncService; + $result = $service->sync($plugin); + + $this->assertTrue($result); + $this->assertEquals('acme/renamed-plugin', $plugin->fresh()->name); + } + + public function test_sync_sets_name_on_initial_sync_when_plugin_has_no_name(): void + { + $composerJson = json_encode([ + 'name' => 'acme/test-plugin', + ]); + + Http::fake([ + 'api.github.com/repos/acme/test-plugin/contents/composer.json' => Http::response([ + 'content' => base64_encode($composerJson), + ]), + 'api.github.com/repos/acme/test-plugin/contents/nativephp.json' => Http::response([], 404), + 'raw.githubusercontent.com/*' => Http::response('', 404), + 'api.github.com/repos/acme/test-plugin/releases/latest' => Http::response([], 404), + 'api.github.com/repos/acme/test-plugin/tags*' => Http::response([]), + 'api.github.com/repos/acme/test-plugin/contents/LICENSE*' => Http::response([], 404), + ]); + + $plugin = Plugin::factory()->create([ + 'name' => null, + 'repository_url' => 'https://github.com/acme/test-plugin', + ]); + + $service = new PluginSyncService; + $result = $service->sync($plugin); + + $this->assertTrue($result); + $this->assertEquals('acme/test-plugin', $plugin->fresh()->name); + } + + public function test_sync_does_not_overwrite_name_when_taken_by_another_plugin(): void + { + $composerJson = json_encode([ + 'name' => 'acme/taken-name', + ]); + + Http::fake([ + 'api.github.com/repos/acme/test-plugin/contents/composer.json' => Http::response([ + 'content' => base64_encode($composerJson), + ]), + 'api.github.com/repos/acme/test-plugin/contents/nativephp.json' => Http::response([], 404), + 'raw.githubusercontent.com/*' => Http::response('', 404), + 'api.github.com/repos/acme/test-plugin/releases/latest' => Http::response([], 404), + 'api.github.com/repos/acme/test-plugin/tags*' => Http::response([]), + 'api.github.com/repos/acme/test-plugin/contents/LICENSE*' => Http::response([], 404), + ]); + + Plugin::factory()->create(['name' => 'acme/taken-name']); + + $plugin = Plugin::factory()->create([ + 'name' => 'acme/original-name', + 'repository_url' => 'https://github.com/acme/test-plugin', + ]); + + $service = new PluginSyncService; + $result = $service->sync($plugin); + + $this->assertTrue($result); + $this->assertEquals('acme/original-name', $plugin->fresh()->name); + } + public function test_sync_sets_mobile_min_version_to_null_when_not_in_composer_data(): void { $composerJson = json_encode([