Skip to content

Instantly share code, notes, and snippets.

@AnandChowdhary
Created March 31, 2025 13:30
Show Gist options
  • Save AnandChowdhary/50e7c352c30b9cb2a8ee5db6d90d9a25 to your computer and use it in GitHub Desktop.
Save AnandChowdhary/50e7c352c30b9cb2a8ee5db6d90d9a25 to your computer and use it in GitHub Desktop.
Changelog automation
import slugify from "@sindresorhus/slugify";
import { execSync } from "child_process";
import dotenv from "dotenv";
import fs from "fs";
import { DateTime } from "luxon";
import { OpenAI } from "openai";
import path from "path";
import prettier from "prettier";
import { env } from "process";
dotenv.config({ path: ".env.local" });
export const openAi = new OpenAI({
baseURL: "https://api.keywordsai.co/api",
apiKey: env.KEYWORDS_AI_API_KEY,
});
async function generateChangelog(end: DateTime) {
const start = end.minus({ weeks: 1 }).startOf("week");
// Format dates for git log command
const startDate = start.toFormat("yyyy-MM-dd");
const endDate = end.toFormat("yyyy-MM-dd");
console.log(`\nπŸ“… Processing week ending ${endDate}...`);
// Check if changelog already exists for this week
const changelogDir = path.join(process.cwd(), "apps", "docs", "changelog");
const existingFiles = fs.readdirSync(changelogDir);
const existingChangelog = existingFiles.find((file) => file.startsWith(endDate));
if (existingChangelog) {
console.log(`⏭️ Changelog already exists for week ending ${endDate}, skipping...`);
return true; // Return true to indicate we should continue
}
try {
// First, get all commit hashes and titles
console.log(`πŸ” Fetching commits from ${startDate} to ${endDate}...`);
const commitsCommand = `git log --pretty=format:"%h : %s" --since="${startDate}" --until="${endDate}"`;
const commits = execSync(commitsCommand, { encoding: "utf-8" })
.split("\n")
.filter((line) => line.trim());
if (commits.length === 0) {
console.log(`πŸ’€ No commits found for week ending ${endDate}`);
return false; // Return false to indicate we found a week with no commits
}
console.log(`πŸ“ Found ${commits.length} commits, processing details...`);
// Process each commit
const processedCommits: string[] = [];
for (const commit of commits) {
const [hash] = commit.split(" : ");
// Get full commit details including body, without diff
const detailsCommand = `git show ${hash} --pretty=format:"%B" --no-patch`;
const details = execSync(detailsCommand, { encoding: "utf-8" })
.split("\n")
.filter((line) => line.trim())
// Remove the first line (commit message) and any empty lines
.slice(1)
.filter((line) => line.trim())
// Split by bullet points and format each one
.map((line) => line.replace(/^-+\s*/, ""))
.filter((line) => line.trim())
.map((line) => ` - ${line}`)
.join("\n");
processedCommits.push(`${commit}${details ? "\n\n" + details : ""}`);
}
console.log(`πŸ€– Generating changelog content with AI...`);
const response = await openAi.chat.completions.create({
// @ts-expect-error - Keywords AI adds extra properties
prompt: { prompt_id: "6b93fa", variables: { details: processedCommits.join("\n\n") } },
});
const text = response.choices[0]?.message?.content ?? "";
// Clean up the AI response
console.log(`🧹 Cleaning up AI response...`);
const cleanedText = text
// Remove everything before the first ###
.replace(/^[\s\S]*?(?=###)/, "")
// Replace ### with ##
.replace(/###/g, "##");
// Extract the first heading for the filename
const firstHeading = cleanedText.match(/^##\s+(.+)$/m)?.[1] ?? "changelog";
const filename = `${endDate}-${slugify(firstHeading)}.mdx`;
// Remove the first heading if it matches the title
const contentWithoutFirstHeading = cleanedText.replace(/^##\s+.+$/m, "").trim();
// Create changelog content with front matter
const changelogContent = `---
title: "${firstHeading}"
description: "Week ${start.weekNumber}, ${start.year} β€” ${start.toFormat("MMMM d")} to ${end.toFormat("MMMM d")}"
---
${contentWithoutFirstHeading}`;
// Write to the changelog file
const changelogPath = path.join(changelogDir, filename);
fs.writeFileSync(changelogPath, await prettier.format(changelogContent, { parser: "markdown" }));
console.log(`✨ Successfully generated changelog at ${changelogPath}`);
return true; // Return true to indicate we should continue
} catch (error) {
console.error(`❌ Error generating changelog for week ending ${endDate}:`, error);
return true; // Return true to continue even if there's an error
}
}
async function generateAllChangelogs() {
console.log(`πŸš€ Starting changelog generation...`);
const end = DateTime.now().endOf("week");
let consecutiveEmptyWeeks = 0;
let currentWeek = end;
while (consecutiveEmptyWeeks < 3) {
const hasCommits = await generateChangelog(currentWeek);
if (!hasCommits) {
consecutiveEmptyWeeks++;
console.log(
`πŸ“Š Found ${consecutiveEmptyWeeks} consecutive week${consecutiveEmptyWeeks === 1 ? "" : "s"} with no commits`,
);
} else {
consecutiveEmptyWeeks = 0; // Reset counter if we found commits
}
currentWeek = currentWeek.minus({ weeks: 1 });
}
console.log(`πŸŽ‰ Finished generating all changelogs!`);
console.log(`πŸ“… Stopped at week ending ${currentWeek.toFormat("yyyy-MM-dd")}`);
}
generateAllChangelogs();

Task

Transform the provided git commit log into a well-organized, user-friendly changelog for our AI sales app. The changelog should highlight the key developments and improvements in a way that's easy for users to understand. While customer-facing changes should be prioritized in the main sections, also include a section for significant internal updates.

Input format

The input will be a markdown formatted list of git commits, typically with commit hashes, types (feat, fix, refactor, etc.), and descriptions. These may include detailed technical information about file changes and implementation details.

Output format

Create a clean, user-focused changelog with the following structure. Ensure all headings, titles, and content use sentence case (capitalize only the first word and proper nouns):

  1. New features - Major new functionality added to the application

    • Create a level 2 heading (## New features) for this section
    • Highlight only the single most significant new feature with a level 3 heading (### Feature name)
    • Include 1-2 short paragraphs describing what the feature does and its benefits to users
    • Combine related commits into a cohesive feature description
    • Only add a second feature if it's truly exceptional and of similar importance as the first
    • All other new features should be added to the Improvements section as bullet points
  2. Improvements - Enhancements to existing functionality

    • Single section with level 2 heading (## Improvements)
    • Bullet point list of improvements
    • Each improvement should be summarized in a single, clear sentence
    • Focus on the user benefit, not technical implementation
    • Include minor features that didn't make the cut for the New Features section
  3. Bug fixes - Issues that have been resolved

    • Single section with level 2 heading (## Fixes)
    • Bullet point list of fixes
    • Each fix should be summarized in a single, clear sentence
    • Describe the issue that was fixed from a user perspective
  4. Behind the scenes - Technical updates and internal improvements

    • Single section with level 2 heading (## Behind the scenes)
    • Bullet point list of internal changes
    • Each item should be summarized in a single, clear sentence
    • Translate technical terminology into simpler language while still accurately describing the update
    • Include only significant internal changes like architectural improvements, performance optimizations, or security enhancements

Guidelines

  • Prioritize customer-facing changes in the first three sections
  • Group internal technical changes in the "Behind the scenes" section
  • Translate technical language into user-friendly terms
  • Group related commits into logical features
  • Prioritize changes that directly impact user experience
  • Remove technical implementation details like file paths, function names, etc.
  • Focus on what changed and why it matters to users
  • Use clear, concise language
  • Present information in order of importance
  • Use consistent formatting throughout
  • Use sentence case for all headings, titles, and content (capitalize only the first word and proper nouns)
  • Keep feature headings short, clear, and to the point (e.g., "Analytics dashboard," "HubSpot integration," "Goal completion API")

Example of feature headings

Keep feature headings short and direct:

  • "Analytics dashboard"
  • "HubSpot integration"
  • "Goal completion API"
  • "Data export"
  • "Email templates"
  • "Contact management"

Full example output

# AI Sales App Changelog: March 24 - April 6, 2025

## New features

### Analytics dashboard

Our new analytics dashboard provides deeper insights into your sales pipeline and customer interactions. You can now track campaign performance, user engagement, and conversion metrics in real-time through an intuitive visual interface.

The dashboard integrates seamlessly with your existing workflows and offers customizable views to focus on the metrics that matter most to your team.

## Improvements

- Added Nylas email and calendar integration for managing communications directly within the app
- Introduced deal pipeline visualization to track opportunities at each sales stage
- Improved email template image quality for more professional-looking campaign messages
- Added support for additional image variables in email templates for more dynamic content
- Upgraded import settings to give you more control over how contacts are added to your database
- Updated the user interface with the Geist font for improved readability and aesthetics
- Added "max" suffix to credits display for clearer understanding of your usage limits
- Redesigned billing progress visuals with usage counts and progress bars for better subscription tracking

## Fixes

- Fixed issues with email draft errors to ensure more reliable message sending
- Corrected campaign preview loading indicator to better reflect the generation process
- Resolved login redirect issues for a smoother authentication experience

## Behind the scenes

- Optimized system logging for improved troubleshooting capabilities
- Standardized API endpoint structure for more consistent performance
- Revamped cookie management for better security and reliability
- Streamlined token handling for more seamless authentication
- Strengthened error handling in draft email processes

This example demonstrates:

  1. A properly formatted heading with date range
  2. A single feature section with descriptive paragraphs and an engaging heading
  3. Concise bullet points for improvements (including minor new features)
  4. Clearly described fixes
  5. Technical updates in the "Behind the scenes" section
  6. Consistent sentence case throughout
  7. User-friendly language that explains benefits
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment