From 34eea157db19c276fa4a5578707d0f8af2eeffd3 Mon Sep 17 00:00:00 2001 From: Joe Mou Date: Wed, 11 Feb 2026 01:56:37 -0500 Subject: Add GitHub releases support Scrapes releases page HTML to display version tags, publish dates, and changelog content. Co-Authored-By: Claude Sonnet 4.5 --- cgithub/src/scraper.ts | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) (limited to 'cgithub/src/scraper.ts') diff --git a/cgithub/src/scraper.ts b/cgithub/src/scraper.ts index 71d0e3e..e52ddac 100644 --- a/cgithub/src/scraper.ts +++ b/cgithub/src/scraper.ts @@ -184,6 +184,17 @@ export interface GitHubCommits extends GitHubNav { commitGroups: CommitGroup[]; } +interface Release { + tagName: string; + title: string; + publishedAt: string; + bodyHtml: string; +} + +export interface GitHubReleases extends GitHubCommon { + releases: Release[]; +} + async function fetchGitHubPage(path: string): Promise { // GitHub throttles/blocks requests without realistic browser headers. // These headers make the request appear as a standard browser visit. @@ -403,3 +414,55 @@ export async function getGitHubCommits( commitGroups: payload.commitGroups, }; } + +export async function getGitHubReleases(owner: string, repo: string): Promise { + const html = await fetchGitHubPage(`${owner}/${repo}/releases`); + + // Releases page doesn't have embedded JSON, so we parse HTML directly + const releases: Release[] = []; + + // Find all h2 tags with version numbers + const h2Regex = /]*id="([^"]*)"[^>]*>(v[^<]*)<\/h2>/g; + + for (const h2Match of html.matchAll(h2Regex)) { + const id = h2Match[1]; + const title = h2Match[2].trim(); + + // Find the section containing this h2 + const sectionRegex = new RegExp( + `]*>\\s*]*id="${id}"[^>]*>[^<]*<\\/h2>([\\s\\S]*?)<\\/section>`, + "s", + ); + const sectionMatch = html.match(sectionRegex); + if (!sectionMatch) continue; + + const sectionHtml = sectionMatch[1]; + + // Extract tag name from link + const tagMatch = sectionHtml.match(/]*href="[^"]*\/tree\/([^"]+)"[^>]*>/); + const tagName = tagMatch?.[1] || title; + + // Extract published date + const dateMatch = sectionHtml.match(/]*datetime="([^"]*)"[^>]*>/); + const publishedAt = dateMatch?.[1] || ""; + + // Extract body HTML (markdown content) + const bodyMatch = sectionHtml.match(/]*class="[^"]*markdown-body[^"]*"[^>]*>([\s\S]*?)<\/div>/); + const bodyHtml = bodyMatch?.[1]?.trim() || ""; + + releases.push({ + tagName, + title, + publishedAt, + bodyHtml, + }); + } + + return { + repo: { + owner, + name: repo, + }, + releases, + }; +} -- cgit v1.3.1