*/ private array $temporaryZipPaths = []; public function test_it_can_publish_zip_without_manifest_using_manual_metadata(): void { $package = Package::query()->create([ 'type' => 'plugin', 'slug' => 'DemoPlugin', 'name' => 'Demo Plugin', 'summary' => '', 'description' => '', 'author' => '', 'homepage' => '', 'icon_url' => '', 'license' => '', 'status' => 'draft', 'is_featured' => false, 'sort_order' => 0, 'download_count' => 0, 'latest_version' => '', ]); $uploadedFile = $this->makeZipUpload($package->slug, [ 'Plugin.php' => 'publishFromZip($package, $uploadedFile, [ 'version' => '1.2.3', 'typecho_min' => '1.2.0', 'typecho_max' => '1.3.*', 'php_min' => '8.0', 'php_max' => '8.3', 'php_extensions' => ['curl', 'json'], 'is_stable' => true, 'mark_as_latest' => true, ]); $this->assertSame('1.2.3', $version->version); $this->assertSame('1.2.0', $version->typecho_min); $this->assertSame('1.3.*', $version->typecho_max); $this->assertSame('8.0', $version->php_min); $this->assertSame('8.3', $version->php_max); $this->assertSame(['curl', 'json'], $version->php_extensions_array); $this->assertTrue($version->is_stable); $this->assertTrue($version->is_latest); $this->assertFileExists(storage_path('app/packages/plugin/DemoPlugin/1.2.3.zip')); $this->assertSame('1.2.3', $package->fresh()->latest_version); } public function test_it_requires_manual_version_when_manifest_is_missing(): void { $package = Package::query()->create([ 'type' => 'plugin', 'slug' => 'DemoPlugin', 'name' => 'Demo Plugin', 'summary' => '', 'description' => '', 'author' => '', 'homepage' => '', 'icon_url' => '', 'license' => '', 'status' => 'draft', 'is_featured' => false, 'sort_order' => 0, 'download_count' => 0, 'latest_version' => '', ]); $uploadedFile = $this->makeZipUpload($package->slug, [ 'Plugin.php' => 'expectException(RuntimeException::class); $this->expectExceptionMessage('manifest.json not found at zip root; version is required for zip publish'); app(VersionPublishService::class)->publishFromZip($package, $uploadedFile, []); } protected function tearDown(): void { foreach ($this->temporaryZipPaths as $path) { if (is_file($path)) { @unlink($path); } } $storedZip = storage_path('app/packages/plugin/DemoPlugin/1.2.3.zip'); if (is_file($storedZip)) { @unlink($storedZip); } $storedDir = storage_path('app/packages/plugin/DemoPlugin'); if (is_dir($storedDir)) { @rmdir($storedDir); } parent::tearDown(); } private function makeZipUpload(string $slug, array $files): UploadedFile { $directory = storage_path('framework/testing'); File::ensureDirectoryExists($directory); $path = tempnam($directory, 'zip'); $this->temporaryZipPaths[] = $path; $zip = new ZipArchive(); $opened = $zip->open($path, ZipArchive::CREATE | ZipArchive::OVERWRITE); if ($opened !== true) { throw new RuntimeException('failed to create test zip'); } foreach ($files as $name => $contents) { $zip->addFromString($slug . '/' . $name, $contents); } $zip->close(); return new UploadedFile($path, $slug . '.zip', 'application/zip', null, true); } }