diff --git a/cli/release_package.php b/cli/release_package.php index c5f83f4..48aadd1 100644 --- a/cli/release_package.php +++ b/cli/release_package.php @@ -250,6 +250,14 @@ class ReleasePackageCli extends CliFramework } $subZipPath = "{$outputDir}/{$subName}.zip"; + // Use pre-built ZIP if staged in the output directory + if (file_exists($subZipPath) && filesize($subZipPath) > 0) { + $zip->addFile($subZipPath, "packages/{$subName}.zip"); + $sizeKb = number_format(filesize($subZipPath) / 1024, 1); + echo " Sub-package: {$subName}.zip (pre-built, {$sizeKb} KB)\n"; + continue; + } + // If sub-package is a full repo checkout (e.g. git submodule), // look for a source/ or src/ subdirectory containing a Joomla manifest XML // and zip that instead of the repo root. @@ -270,6 +278,16 @@ class ReleasePackageCli extends CliFramework } } + // If source dir has no manifest, the submodule may be empty. + // Try to download the pre-built release from Gitea. + $hasManifest = !empty(glob("{$subSourceDir}/*.xml") ?: []); + if (!$hasManifest && $token !== '' && $this->downloadSubmoduleRelease($root, $subName, $subZipPath, $token)) { + $zip->addFile($subZipPath, "packages/{$subName}.zip"); + $sizeKb = number_format(filesize($subZipPath) / 1024, 1); + echo " Sub-package: {$subName}.zip (downloaded release, {$sizeKb} KB)\n"; + continue; + } + $subZip = new \ZipArchive(); if ($subZip->open($subZipPath, \ZipArchive::CREATE | \ZipArchive::OVERWRITE) !== true) { $this->log('ERROR', "Failed to create sub-package ZIP: {$subZipPath}"); @@ -527,6 +545,103 @@ class ReleasePackageCli extends CliFramework return false; } + /** + * Download a pre-built release ZIP for a sub-package that is a git submodule + * with an empty or missing source directory. + * + * Reads .gitmodules to find the submodule's remote URL, derives the Gitea + * API path, and downloads the latest stable release asset. + */ + private function downloadSubmoduleRelease(string $root, string $subName, string $destPath, string $token): bool + { + $gitmodulesPath = "{$root}/.gitmodules"; + if (!file_exists($gitmodulesPath)) { + return false; + } + + $gitmodules = file_get_contents($gitmodulesPath); + if ($gitmodules === false) { + return false; + } + + // Find the submodule URL by matching the subName in the path + if (!preg_match('/\[submodule\s[^\]]*\]\s*\n\s*path\s*=\s*[^\n]*' . preg_quote($subName, '/') . '\s*\n\s*url\s*=\s*(\S+)/m', $gitmodules, $matches)) { + return false; + } + + $remoteUrl = preg_replace('/\.git$/', '', $matches[1]); + + // Extract org/repo from the URL + if (!preg_match('#[/:]([^/]+)/([^/]+)$#', $remoteUrl, $parts)) { + return false; + } + + $org = $parts[1]; + $repo = $parts[2]; + + // Derive the Gitea API base from the remote URL + $parsed = parse_url($remoteUrl); + $scheme = $parsed['scheme'] ?? 'https'; + $host = $parsed['host'] ?? ''; + if ($host === '') { + return false; + } + $apiBase = "{$scheme}://{$host}/api/v1/repos/{$org}/{$repo}"; + + echo " Submodule {$subName}: source empty, downloading release from {$org}/{$repo}...\n"; + + // Get the stable release + $result = $this->giteaApiRequest("{$apiBase}/releases/tags/stable", $token); + if ($result['data'] === null || !isset($result['data']['assets'])) { + echo " WARNING: No stable release found for {$org}/{$repo}\n"; + return false; + } + + // Find the ZIP asset (not .sha256) + $downloadUrl = ''; + foreach ($result['data']['assets'] as $asset) { + if (!is_array($asset)) { + continue; + } + $name = $asset['name'] ?? ''; + if (str_ends_with($name, '.zip') && !str_ends_with($name, '.sha256')) { + $downloadUrl = $asset['browser_download_url'] ?? ''; + break; + } + } + + if ($downloadUrl === '') { + echo " WARNING: No ZIP asset in {$org}/{$repo} stable release\n"; + return false; + } + + // Download the ZIP + $ch = curl_init($downloadUrl); + if ($ch === false) { + return false; + } + curl_setopt_array($ch, [ + CURLOPT_RETURNTRANSFER => true, + CURLOPT_FOLLOWLOCATION => true, + CURLOPT_HTTPHEADER => ["Authorization: token {$token}"], + CURLOPT_TIMEOUT => 120, + ]); + $content = curl_exec($ch); + $httpCode = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + + if ($httpCode < 200 || $httpCode >= 300 || !is_string($content) || $content === '') { + echo " WARNING: Download failed (HTTP {$httpCode})\n"; + return false; + } + + if (file_put_contents($destPath, $content) === false) { + return false; + } + + return true; + } + /** * Recursively add files from a directory to a ZipArchive. */