Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 18 additions & 11 deletions .github/prompts/generate-changelog.md
Original file line number Diff line number Diff line change
@@ -1,35 +1,41 @@
# Weekly Changelog Generation
# Changelog Generation for Release

Generate a new changelog entry for this week based on merged PRs.
Generate a new changelog entry for this release based on merged PRs since the previous tag.

The version number is provided at the top of the prompt as `Version: X.Y.Z`.

## Instructions

1. **Find PRs merged since last Monday**
- Use `gh pr list --state merged --search "merged:>=$(date -d 'last monday' +%Y-%m-%d)" --json number,title,body,url,mergedAt --limit 50` to get all PRs merged in the past week
1. **Find PRs merged since the previous tag**
- Find the previous `desktop-v*` tag: `git tag --sort=-v:refname -l "desktop-v*" | head -2 | tail -1` to get the second-most-recent tag (alternatively try `git describe --tags --abbrev=0 --match "desktop-v*" HEAD^ 2>/dev/null` if HEAD is the tagged commit)
- Get the date of that tag: `git log -1 --format=%aI <previous-tag>`
- Use `gh pr list --state merged --search "merged:>=$(date -d '<tag-date>' +%Y-%m-%d 2>/dev/null || date -j -f '%Y-%m-%dT%H:%M:%S%z' '<tag-date>' +%Y-%m-%d)" --json number,title,body,url,mergedAt --limit 50` to get all PRs merged since the previous tag
- Categorize PRs into: **Major features**, **Improvements**, **Bug fixes**
- Skip PRs that are purely internal (CI/CD, dev tooling, refactors) unless they affect users

2. **Check for existing changelog**
- Before creating a new file, check if a changelog already exists for this week's date
- Use `ls apps/marketing/content/changelog/` to see existing files
- If a file for today's date already exists, skip creation and report that a changelog already exists
- Before creating a new file, check if a changelog already exists for this version
- Use `grep -rl "version: X.Y.Z" apps/marketing/content/changelog/` to search for existing files with this version in frontmatter
- If a file for this version already exists, skip creation and report that a changelog already exists

3. **Prioritize content**
- **Lead with 2-4 major features** - These get their own sections with full descriptions
- **Group smaller improvements** - Can combine related small changes under one heading
- **Bug fixes go in a footnote section** - Brief one-liner summaries at the bottom

4. **Create the changelog file**
- Create a new file at: `apps/marketing/content/changelog/YYYY-MM-DD-slug.mdx`
- Use today's date for the filename (e.g., `2026-01-27-descriptive-slug.mdx`)
- The slug should summarize the main features (e.g., `terminal-improvements`, `sidebar-workspaces`)
- Create a new file at: `apps/marketing/content/changelog/YYYY-MM-DD-descriptive-slug.mdx`
- Use today's date and a short descriptive slug based on the main features (e.g., `2026-02-16-in-app-browser.mdx`)
- The slug should be SEO-friendly and summarize the key changes (e.g., `terminal-improvements`, `sidebar-workspaces`)
- Do NOT put the version number in the filename — the version lives in frontmatter only

5. **Follow this exact format**:

```mdx
---
title: Brief title highlighting 1-2 main features
date: YYYY-MM-DD
version: X.Y.Z
image: /changelog/IMAGE_PLACEHOLDER.png
---

Expand Down Expand Up @@ -59,6 +65,7 @@ Brief description of the feature and its benefit to users.
6. **Important formatting rules**
- Frontmatter (`---`) must be at the very top of the file with no content before it
- MDX comments (`{/* ... */}`) must come AFTER the frontmatter, not before
- Include `version: X.Y.Z` in the frontmatter (use the version number provided, without the `v` prefix)
- Set `image:` in frontmatter to `/changelog/IMAGE_PLACEHOLDER.png` - reviewers will replace this
- Add TODO comments for features that would benefit from screenshots
- Use a horizontal rule (`---`) before the bug fixes footnote
Expand Down Expand Up @@ -89,4 +96,4 @@ Read these files to understand the expected format:

## Output

Create exactly one new changelog file. If there are no significant PRs to report or a changelog already exists for this week, do not create a file and report why.
Create exactly one new changelog file. If there are no significant PRs to report or a changelog already exists for this version, do not create a file and report why.
57 changes: 45 additions & 12 deletions .github/workflows/generate-changelog.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
name: Generate Changelog

on:
schedule:
# Run every Monday at 9:00 AM UTC
- cron: "0 9 * * 1"
workflow_dispatch: # Allow manual triggering
release:
types: [published]
workflow_dispatch:
inputs:
version:
description: "Version number (e.g. 0.0.76)"
required: true

jobs:
generate-changelog:
Expand All @@ -20,6 +23,26 @@ jobs:
with:
fetch-depth: 0

- name: Extract version
id: version
env:
INPUT_VERSION: ${{ github.event.inputs.version }}
RELEASE_TAG: ${{ github.event.release.tag_name }}
EVENT_NAME: ${{ github.event_name }}
run: |
if [ "$EVENT_NAME" = "workflow_dispatch" ]; then
VERSION="$INPUT_VERSION"
else
# Extract version from release tag: desktop-v0.0.76 -> 0.0.76
VERSION="${RELEASE_TAG#desktop-v}"
fi
if ! echo "$VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+$'; then
echo "::error::Invalid version format: $VERSION (expected X.Y.Z)"
exit 1
fi
echo "VERSION=$VERSION" >> $GITHUB_ENV
echo "version=$VERSION" >> $GITHUB_OUTPUT
Comment thread
coderabbitai[bot] marked this conversation as resolved.

- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
Expand All @@ -35,11 +58,11 @@ jobs:
run: bun install --frozen

- name: Install Claude Code
run: npm install -g @anthropic-ai/claude-code
run: bun install -g @anthropic-ai/claude-code

- name: Create branch
run: |
BRANCH_NAME="changelog/$(date +%Y-%m-%d)-${GITHUB_RUN_ID}"
BRANCH_NAME="changelog/v${VERSION}-${GITHUB_RUN_ID}"
git checkout -B "$BRANCH_NAME"
echo "BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_ENV

Expand All @@ -48,7 +71,11 @@ jobs:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
claude -p "$(cat .github/prompts/generate-changelog.md)" --allowedTools "Bash(git*)" "Bash(gh*)" "Bash(date*)" "Bash(ls*)" "Read" "Write" "Edit" "Glob" "Grep"
{
echo "Version: $VERSION"
echo ""
cat .github/prompts/generate-changelog.md
} | claude -p --allowedTools "Bash(git*)" "Bash(gh*)" "Bash(date*)" "Bash(ls*)" "Read" "Write" "Edit" "Glob" "Grep"

- name: Check for changes
id: check-changes
Expand All @@ -69,24 +96,30 @@ jobs:
git config --local user.email "github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"
git add -A
git commit -m "docs: generate weekly changelog $(date +%Y-%m-%d)"
git commit -m "docs: generate changelog for v${VERSION}"
git push origin "$BRANCH_NAME"

- name: Create Pull Request
if: steps.check-changes.outputs.has_changes == 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
EVENT_NAME: ${{ github.event_name }}
run: |
CURRENT_DATE=$(date +%Y-%m-%d)
TAG_LINE=""
if [ "$EVENT_NAME" = "release" ]; then
TAG_LINE="- **Tag**: desktop-v${VERSION}"
fi

gh pr create \
--reviewer kitenite --reviewer saddlepaddle --reviewer AviPeltz \
--title "docs: weekly changelog - $CURRENT_DATE" \
--title "docs: changelog for v${VERSION}" \
--body "## Summary
This PR was automatically generated by Claude Code to create the weekly changelog.
This PR was automatically generated by Claude Code to create the changelog for v${VERSION}.

## Details
- **Prompt file**: \`.github/prompts/generate-changelog.md\`
- **Generated on**: $CURRENT_DATE
- **Version**: v${VERSION}
${TAG_LINE}

## Review Checklist
- [ ] Replace \`IMAGE_PLACEHOLDER.png\` with actual screenshot
Expand Down
2 changes: 1 addition & 1 deletion apps/marketing/src/app/changelog.xml/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export async function GET() {
.map(
(entry) => `
<item>
<title>${escapeXml(entry.title)}</title>
<title>${entry.version ? `v${escapeXml(entry.version)} — ` : ""}${escapeXml(entry.title)}</title>
<link>${baseUrl}/changelog/${entry.slug}</link>
<description>${escapeXml(entry.description || "")}</description>
<pubDate>${new Date(entry.date).toUTCString()}</pubDate>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import type { ReactNode } from "react";
import { GridCross } from "@/app/blog/components/GridCross";
import {
type ChangelogEntry,
formatChangelogDate,
formatVersionDate,
} from "@/lib/changelog-utils";

interface ChangelogEntryLayoutProps {
Expand All @@ -18,8 +18,6 @@ export function ChangelogEntryLayout({
entry,
children,
}: ChangelogEntryLayoutProps) {
const formattedDate = formatChangelogDate(entry.date);

return (
<article className="relative min-h-screen">
{/* Grid background with dashed lines */}
Expand All @@ -44,7 +42,7 @@ export function ChangelogEntryLayout({
dateTime={entry.date}
className="text-sm font-mono text-muted-foreground uppercase tracking-wider"
>
{formattedDate}
{formatVersionDate(entry.version, entry.date)}
</time>

<h1 className="text-3xl md:text-4xl lg:text-5xl font-medium tracking-tight text-foreground mt-4 mb-4">
Expand Down
4 changes: 2 additions & 2 deletions apps/marketing/src/app/changelog/[slug]/opengraph-image.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import fs from "node:fs";
import path from "node:path";
import { ImageResponse } from "next/og";
import { getChangelogEntry } from "@/lib/changelog";
import { formatChangelogDate } from "@/lib/changelog-utils";
import { formatVersionDate } from "@/lib/changelog-utils";

export const alt = "Superset Changelog";
export const size = { width: 1200, height: 630 };
Expand Down Expand Up @@ -142,7 +142,7 @@ export default async function Image({
{entry.title}
</div>
<div style={{ fontSize: 24, color: "#999999" }}>
{formatChangelogDate(entry.date)}
{formatVersionDate(entry.version, entry.date)}
</div>
</div>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,14 @@ import Image from "next/image";
import Link from "next/link";
import {
type ChangelogEntry,
formatChangelogDate,
formatVersionDate,
} from "@/lib/changelog-utils";

interface ChangelogCardProps {
entry: ChangelogEntry;
}

export function ChangelogCard({ entry }: ChangelogCardProps) {
const formattedDate = formatChangelogDate(entry.date);

return (
<Link href={entry.url} className="block group">
<article className="border border-border bg-background transition-all hover:bg-muted/50 hover:border-foreground/20">
Expand All @@ -30,7 +28,7 @@ export function ChangelogCard({ entry }: ChangelogCardProps) {
dateTime={entry.date}
className="text-sm font-mono text-muted-foreground"
>
{formattedDate}
{formatVersionDate(entry.version, entry.date)}
</time>
<h2 className="text-xl font-medium text-foreground mt-2 mb-2 group-hover:text-foreground/90">
{entry.title}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import Link from "next/link";
import { MDXRemote } from "next-mdx-remote/rsc";
import {
type ChangelogEntry as ChangelogEntryType,
formatChangelogDate,
formatVersionDate,
} from "@/lib/changelog-utils";
import { changelogMdxComponents } from "./changelog-mdx-components";

Expand All @@ -11,8 +11,6 @@ interface ChangelogEntryProps {
}

export async function ChangelogEntry({ entry }: ChangelogEntryProps) {
const formattedDate = formatChangelogDate(entry.date);

return (
<article
id={`changelog-${entry.slug}`}
Expand All @@ -25,7 +23,7 @@ export async function ChangelogEntry({ entry }: ChangelogEntryProps) {
>
<div className="sticky top-24 flex items-center gap-3 pt-1">
<span className="text-sm font-mono text-muted-foreground whitespace-nowrap">
{formattedDate}
{formatVersionDate(entry.version, entry.date)}
</span>
<div className="w-0.5 h-5 bg-orange-500" />
</div>
Expand All @@ -36,7 +34,7 @@ export async function ChangelogEntry({ entry }: ChangelogEntryProps) {
dateTime={entry.date}
className="lg:hidden block text-sm font-mono text-muted-foreground mb-4"
>
{formattedDate}
{formatVersionDate(entry.version, entry.date)}
</time>

{/* Title */}
Expand Down
10 changes: 10 additions & 0 deletions apps/marketing/src/lib/changelog-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export interface ChangelogEntry {
title: string;
description?: string;
date: string;
version?: string;
image?: string;
content: string;
}
Expand All @@ -20,3 +21,12 @@ export { slugify } from "./content-utils";
export function formatChangelogDate(date: string): string {
return formatContentDate(date, "long");
}

export function formatVersionDate(
version: string | undefined,
date: string,
separator = "·",
): string {
const formatted = formatChangelogDate(date);
return version ? `v${version} ${separator} ${formatted}` : formatted;
}
3 changes: 2 additions & 1 deletion apps/marketing/src/lib/changelog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { normalizeContentDate } from "./content-utils";

export {
type ChangelogEntry,
formatChangelogDate,
formatVersionDate,
slugify,
} from "./changelog-utils";

Expand All @@ -26,6 +26,7 @@ function parseFrontmatter(filePath: string): ChangelogEntry | null {
title: data.title ?? "Untitled",
description: data.description,
date: dateValue,
version: data.version,
image: data.image,
content,
};
Expand Down