where('key', 'version')->value('value'); if (!$version) { $this->error('Unable to determine version from settings.'); return self::FAILURE; } $token = env('GITEA_TOKEN'); $owner = env('GITEA_OWNER'); $repo = env('GITEA_REPO'); $apiBase = rtrim((string) env('GITEA_API_BASE', 'https://git.24unix.net/api/v1'), '/'); $target = $this->option('target') ?: env('GITEA_TARGET_COMMIT', 'master'); $prerelease = $this->option('prerelease') || filter_var(env('GITEA_PRERELEASE', false), FILTER_VALIDATE_BOOLEAN); if (!$token || !$owner || !$repo) { $this->error('Missing Gitea config. Set GITEA_TOKEN, GITEA_OWNER, and GITEA_REPO in .env.'); return self::FAILURE; } $tag = "v{$version}"; $body = $this->resolveChangelogBody($version); $client = Http::withHeaders([ 'Authorization' => "token {$token}", 'Accept' => 'application/json', ]); $payload = [ 'tag_name' => $tag, 'target_commitish' => $target, 'name' => $tag, 'body' => $body, 'prerelease' => (bool) $prerelease, ]; $createUrl = "{$apiBase}/repos/{$owner}/{$repo}/releases"; $response = $client->post($createUrl, $payload); if ($response->successful()) { $this->info("Release created: {$tag}"); return self::SUCCESS; } if ($response->status() === 409 || $response->status() === 422) { $getUrl = "{$apiBase}/repos/{$owner}/{$repo}/releases/tags/{$tag}"; $existing = $client->get($getUrl); if (!$existing->successful()) { $this->error('Release already exists, but failed to fetch it for update.'); return self::FAILURE; } $id = $existing->json('id'); if (!$id) { $this->error('Release already exists, but no ID was returned.'); return self::FAILURE; } $updateUrl = "{$apiBase}/repos/{$owner}/{$repo}/releases/{$id}"; $updatePayload = [ 'name' => $tag, 'body' => $body, 'prerelease' => (bool) $prerelease, 'target_commitish' => $target, ]; $updated = $client->patch($updateUrl, $updatePayload); if ($updated->successful()) { $this->info("Release updated: {$tag}"); return self::SUCCESS; } $this->error("Failed to update release: {$updated->status()}"); return self::FAILURE; } $this->error("Failed to create release: {$response->status()}"); return self::FAILURE; } private function resolveChangelogBody(string $version): string { $path = base_path('CHANGELOG.md'); if (!is_file($path) || !is_readable($path)) { return 'See commit history for details.'; } $raw = file_get_contents($path); if ($raw === false) { return 'See commit history for details.'; } $pattern = '/^##\\s+' . preg_quote($version, '/') . '\\s*\\R(.*?)(?=^##\\s+|\\z)/ms'; if (preg_match($pattern, $raw, $matches)) { $body = trim($matches[1] ?? ''); return $body !== '' ? $body : 'See commit history for details.'; } return 'See commit history for details.'; } }