From b60a91a0757c003d20a6476755892a74073c1dab Mon Sep 17 00:00:00 2001
From: "Abdullah." <125115953+mabdullahabaid@users.noreply.github.com>
Date: Fri, 5 Jun 2026 13:59:40 +0500
Subject: [PATCH] fix(website): render releases from local notes, drop GitHub
gate (#21238)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The releases page gated visible notes on fetchLatestGithubReleaseTag();
when that unauthenticated GitHub call was rate-limited at build (common
on shared Cloudflare build IPs, no GITHUB_TOKEN), it returned null and
getVisibleReleaseNotes returned [], rendering 'No releases are visible
yet for the current published version' — the exact prod symptom.
force-static made each deploy a coin flip.
Committed MDX (+images) is the single source of truth, so gate
visibility on nothing: render all local notes deterministically with no
network call. Removes the dev/prod divergence and deletes the now-dead
fetch-latest-release-tag.ts and get-visible-releases.ts.
---
.../src/app/[locale]/releases/page.tsx | 25 ++++-----------
.../lib/releases/fetch-latest-release-tag.ts | 24 --------------
.../src/lib/releases/get-visible-releases.ts | 32 -------------------
3 files changed, 7 insertions(+), 74 deletions(-)
delete mode 100644 packages/twenty-website/src/lib/releases/fetch-latest-release-tag.ts
delete mode 100644 packages/twenty-website/src/lib/releases/get-visible-releases.ts
diff --git a/packages/twenty-website/src/app/[locale]/releases/page.tsx b/packages/twenty-website/src/app/[locale]/releases/page.tsx
index b639f592a2..88b47ca329 100644
--- a/packages/twenty-website/src/app/[locale]/releases/page.tsx
+++ b/packages/twenty-website/src/app/[locale]/releases/page.tsx
@@ -1,8 +1,6 @@
import { fetchCommunityStats } from '@/lib/community/fetch-community-stats';
import { getRouteI18n, type LocaleRouteParams } from '@/lib/i18n/server';
import { mergeSocialLinkLabels } from '@/lib/community/merge-social-link-labels';
-import { fetchLatestGithubReleaseTag } from '@/lib/releases/fetch-latest-release-tag';
-import { getVisibleReleaseNotes } from '@/lib/releases/get-visible-releases';
import { loadLocalReleaseNotes } from '@/lib/releases/load-local-release-notes';
import { ReleasesHero } from '@/app/[locale]/releases/_components/ReleasesHero';
import { Menu, MENU_DATA } from '@/sections/Menu';
@@ -25,22 +23,17 @@ type ReleasesPageProps = {
};
export default async function ReleasesPage({ params }: ReleasesPageProps) {
- const allNotes = loadLocalReleaseNotes();
- const [, latestTag, stats] = await Promise.all([
+ const notes = loadLocalReleaseNotes();
+ const [, stats] = await Promise.all([
getRouteI18n(params),
- fetchLatestGithubReleaseTag(),
fetchCommunityStats(),
]);
const menuSocialLinks = mergeSocialLinkLabels(MENU_DATA.socialLinks, stats);
- const visibleNotes =
- process.env.NODE_ENV === 'development'
- ? allNotes
- : getVisibleReleaseNotes(allNotes, latestTag);
return (
<>
- {visibleNotes.length > 0 ? (
-
+ {notes.length > 0 ? (
+
) : null}
{/*
* Above-the-fold milestone scene texture. Preload kicks off the
@@ -59,26 +52,22 @@ export default async function ReleasesPage({ params }: ReleasesPageProps) {
- {allNotes.length === 0 ? (
+ {notes.length === 0 ? (
Releases were not found. Add MDX under{' '}
packages/twenty-website/src/content/releases and
images under{' '}
packages/twenty-website/public/images/releases.
- ) : visibleNotes.length === 0 ? (
-
- No releases are visible yet for the current published version.
-
) : (
- visibleNotes.map((note, index) => (
+ notes.map((note, index) => (
- {index < visibleNotes.length - 1 ? : null}
+ {index < notes.length - 1 ? : null}
))
)}
diff --git a/packages/twenty-website/src/lib/releases/fetch-latest-release-tag.ts b/packages/twenty-website/src/lib/releases/fetch-latest-release-tag.ts
deleted file mode 100644
index 5197b06252..0000000000
--- a/packages/twenty-website/src/lib/releases/fetch-latest-release-tag.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-export async function fetchLatestGithubReleaseTag(): Promise {
- try {
- const headers: Record = {
- Accept: 'application/vnd.github+json',
- 'X-GitHub-Api-Version': '2022-11-28',
- };
-
- if (process.env.GITHUB_TOKEN) {
- headers.Authorization = `Bearer ${process.env.GITHUB_TOKEN}`;
- }
-
- const response = await fetch(
- 'https://api.github.com/repos/twentyhq/twenty/releases/latest',
- { headers },
- );
-
- if (!response.ok) return null;
-
- const data = (await response.json()) as { tag_name?: string };
- return data.tag_name ?? null;
- } catch {
- return null;
- }
-}
diff --git a/packages/twenty-website/src/lib/releases/get-visible-releases.ts b/packages/twenty-website/src/lib/releases/get-visible-releases.ts
deleted file mode 100644
index 0b865ba303..0000000000
--- a/packages/twenty-website/src/lib/releases/get-visible-releases.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-import type { LocalReleaseNote } from '@/lib/releases/types';
-import { getFormattedReleaseNumber } from '@/lib/releases/get-formatted-release-number';
-
-function safeReleaseNumber(version: string): number | null {
- try {
- return getFormattedReleaseNumber(version);
- } catch {
- return null;
- }
-}
-
-export function getVisibleReleaseNotes(
- notes: LocalReleaseNote[],
- latestPublishedTag: string | null,
-): LocalReleaseNote[] {
- if (!latestPublishedTag) {
- return [];
- }
-
- const publishedNumber = safeReleaseNumber(latestPublishedTag);
- if (publishedNumber === null) {
- return [];
- }
-
- return notes.filter((note) => {
- const noteNumber = safeReleaseNumber(note.release);
- if (noteNumber === null) {
- return false;
- }
- return noteNumber <= publishedNumber;
- });
-}