feat(changelog): extract and display published date for changelog entries#1465
feat(changelog): extract and display published date for changelog entries#1465arnestrickmann merged 1 commit intomainfrom
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Greptile SummaryThis PR adds published-date extraction and display to the changelog feature. When the JSON API response lacks a Key changes:
Issues found:
Confidence Score: 3/5
|
| Filename | Overview |
|---|---|
| src/main/services/ChangelogService.ts | Adds regex-based date extraction, fetchHtml helper, and withResolvedHtmlPublishedAt fallback; ISO_DATE_REGEX contains an unintentional character-class range ([0-9:.+-Z] should be [0-9:.\-+Z]) |
| src/renderer/lib/changelogDate.ts | New shared date-formatting helper extracted from ChangelogModal; ISO date-only strings (e.g. "2026-03-13") are parsed as UTC midnight, causing the formatted day to be off by one for users in negative-UTC-offset timezones |
| src/renderer/components/ChangelogModal.tsx | Replaces the inline formatPublishedAt with the shared formatChangelogPublishedAt helper and wraps the date in a Badge component; no logic changes beyond the extraction |
| src/renderer/components/sidebar/ChangelogNotificationCard.tsx | Adds the publishedAt badge above the title using the shared helper; straightforward addition with no logic issues |
| src/test/main/ChangelogService.test.ts | Adds two tests covering date inference from rendered HTML and prevention of cross-version date assignment; both tests are well-scoped and use human-readable date strings (no ISO-only date coverage) |
Sequence Diagram
sequenceDiagram
participant App
participant ChangelogService
participant JsonAPI as JSON API
participant HtmlPage as HTML Changelog Page
participant Renderer
App->>ChangelogService: getLatestEntry(version)
loop For each API URL
ChangelogService->>JsonAPI: fetchJson(apiUrl)
JsonAPI-->>ChangelogService: payload (may lack publishedAt)
alt match found with publishedAt
ChangelogService-->>App: ChangelogEntry (complete)
else match found, publishedAt missing
ChangelogService->>HtmlPage: fetchHtml(EMDASH_CHANGELOG_URL)
HtmlPage-->>ChangelogService: html
ChangelogService->>ChangelogService: parseChangelogHtml(html, version)
note over ChangelogService: extractTime OR extractPublishedAtForVersion
ChangelogService-->>App: ChangelogEntry (publishedAt enriched)
end
end
alt no JSON match at all
ChangelogService->>HtmlPage: fetchHtml(EMDASH_CHANGELOG_URL)
HtmlPage-->>ChangelogService: html
ChangelogService->>ChangelogService: parseChangelogHtml(html, version)
ChangelogService-->>App: ChangelogEntry (or null)
end
App->>Renderer: pass ChangelogEntry
Renderer->>Renderer: formatChangelogPublishedAt(publishedAt)
Renderer-->>App: Badge with formatted date
Last reviewed commit: fa7747a
| const MONTH_NAME_PATTERN = | ||
| '(?:Jan(?:uary)?|Feb(?:ruary)?|Mar(?:ch)?|Apr(?:il)?|May|Jun(?:e)?|Jul(?:y)?|Aug(?:ust)?|Sep(?:t(?:ember)?)?|Oct(?:ober)?|Nov(?:ember)?|Dec(?:ember)?)'; | ||
| const HUMAN_DATE_REGEX = new RegExp(`\\b(${MONTH_NAME_PATTERN}\\s+\\d{1,2},\\s+\\d{4})\\b`, 'i'); | ||
| const ISO_DATE_REGEX = /\b(\d{4}-\d{2}-\d{2}(?:[tT][0-9:.+-Z]*)?)\b/; |
There was a problem hiding this comment.
Unintentional character-class range in ISO_DATE_REGEX
The character class [0-9:.+-Z] contains an unintended ASCII range. In a regex character class, a bare - between two characters creates a range. Here + is ASCII 43 and Z is ASCII 90, so +-Z matches all characters from ASCII 43–90 — including ,, /, ;, <, =, >, ?, @, and all uppercase letters A–Y. The intent is clearly to match ISO 8601 time-segment characters (digits, colon, period, plus, hyphen, and the literal Z). The hyphen must either be escaped or placed at the start/end of the class to be treated as a literal.
| const ISO_DATE_REGEX = /\b(\d{4}-\d{2}-\d{2}(?:[tT][0-9:.+-Z]*)?)\b/; | |
| const ISO_DATE_REGEX = /\b(\d{4}-\d{2}-\d{2}(?:[tT][0-9:.\-+Z]*)?)\b/; |
| const parsed = new Date(value); | ||
| if (Number.isNaN(parsed.getTime())) return value; |
There was a problem hiding this comment.
ISO date-only strings parsed as UTC midnight, causing off-by-one day for users in negative-offset timezones
When value is an ISO date-only string such as "2026-03-13" (without a time component), the ECMAScript specification mandates that new Date("2026-03-13") is parsed as UTC midnight. Intl.DateTimeFormat then formats this in the user's local timezone. For any user whose timezone is behind UTC (UTC-1 through UTC-12, covering all of the Americas), the displayed date will be one day earlier — March 12 instead of March 13. This is a user-visible regression that will affect the badge in both the changelog modal and the sidebar notification card.
This PR introduces new paths that can write ISO date-only strings into publishedAt via ISO_DATE_REGEX (e.g. an HTML heading like "2026-03-13 v0.4.32" extracts "2026-03-13"). The same bug pre-existed for <time datetime="2026-03-13">, but this PR widens the surface.
To prevent the timezone shift, parse date-only strings explicitly as local midnight instead of UTC:
| const parsed = new Date(value); | |
| if (Number.isNaN(parsed.getTime())) return value; | |
| const parsed = /^\d{4}-\d{2}-\d{2}$/.test(value) | |
| ? new Date(`${value}T00:00:00`) | |
| : new Date(value); |
Adding a local-time suffix (T00:00:00, no Z) causes the engine to parse the date in local time, so the rendered day always matches what was authored.
Summary
<time>tag is present, supporting both human-readable (e.g. "March 13, 2026") and ISO date formats adjacent to version stringspublishedAt, fall back to HTML scraping to resolve the dateBadgein both the changelog modal and sidebar notification cardformatChangelogPublishedAthelper intosrc/renderer/lib/changelogDate.tsfor reuseChanges
ChangelogService.ts— Added regex-based date extraction (extractPublishedAtForVersion,extractPublishedAtFromText),fetchHtmlhelper, andwithResolvedHtmlPublishedAtfallback. JSON-sourced entries now attempt HTML enrichment whenpublishedAtis missing.ChangelogModal.tsx— Replaced inlineformatPublishedAtwith shared helper; renders date in aBadgecomponentChangelogNotificationCard.tsx— Added published date display as aBadgeabove the titlechangelogDate.ts— New shared date formatting utility extracted from the modalChangelogService.test.ts— Added tests for date inference from rendered content and for avoiding incorrect cross-version date assignmentTest plan
pnpm exec vitest runpasses, including the two newparseChangelogHtmltests<time>tags