Got multiple repos that you want to serve changelog updates for?
If your repositories follow the Keep a Changelog convention, here's all you need to do:
- Check out your repos on the same machine running this server
- Add them to your .env configuration
- That's it - your changelogs are now served via a clean REST API
Want to keep them updated? Simply schedule a git pull for all your repos with a cron job and you're done. No manual work needed.
Once running, your apps can get updates by calling:
GET your-domain/repos/my-project/since/1.2.0
Returns a markdown response like:
# New updates!
## Added
- [2.1.0] Real-time notifications
- [2.0.0] Complete UI redesign
## Fixed
- [2.1.0] Memory leak in data processingWith WITH_DATES=true:
# New updates!
## Added
- [2.1.0] (Apr 25, 2025) Real-time notifications
- [2.0.0] (Mar 15, 2025) Complete UI redesign
## Fixed
- [2.1.0] (Apr 25, 2025) Memory leak in data processing- 🚀 Fast API server built with Bun - serve multiple repo changelogs instantly
- 📋 Keep a Changelog parser - works with the standard format out of the box
- 🔄 Dynamic configuration - add/remove repos via environment variables
- 📚 RESTful JSON & Markdown APIs - get structured data or formatted diffs
- ⚡ Optional SQLite caching - 80% faster responses for high-traffic scenarios
- ✅ Zero maintenance - just pull your repos and the server handles the rest
- Bun installed on your system
- Repository folders with
CHANGELOG.mdfiles in Keep a Changelog format
- Clone this repository:
git clone <repository-url>
cd changelogger- Install dependencies:
bun install- Create your environment configuration:
cp .env.example .env- Edit
.envto configure your repositories:
PORT=3000
REPOS=my-project,another-project,third-project
# Optional: REPOS_BASE_PATH=/path/to/repos- Start the server:
# Development mode (with hot reload)
bun run dev
# Production mode
bun run startBase URL: http://localhost:3000
Health check endpoint.
Response:
{
"success": true,
"data": {
"status": "healthy",
"timestamp": "2024-01-01T12:00:00.000Z",
"repos": 3,
"validRepos": 2
}
}Get list of all configured repositories.
Response:
{
"success": true,
"data": {
"repositories": ["my-project", "another-project"]
}
}Get full changelog for a specific repository.
Parameters:
repo(string): Repository name
Response:
{
"success": true,
"data": {
"name": "my-project",
"path": "./my-project",
"unreleased": {
"added": [
{"description": "New feature coming soon"}
]
},
"versions": [
{
"version": "1.0.0",
"date": "2024-01-01",
"changes": {
"added": [
{"description": "Initial release"}
],
"fixed": [
{"description": "Critical bug fix"}
]
}
}
]
}
}Get the latest version information for a repository.
Parameters:
repo(string): Repository name
Response:
{
"success": true,
"data": {
"version": "1.0.0",
"date": "2024-01-01",
"changes": {
"added": [
{"description": "Initial release"}
]
}
}
}Get specific version details for a repository.
Parameters:
repo(string): Repository nameversion(string): Version identifier
Response:
{
"success": true,
"data": {
"version": "1.0.0",
"date": "2024-01-01",
"changes": {
"added": [
{"description": "Initial release"}
]
}
}
}Get the complete changelog in markdown format for a repository.
Parameters:
repo(string): Repository name
Query Parameters:
title(string, optional): Custom title for the markdown output (max 128 chars, sanitized)
Response:
# Complete Changelog
## Added
- [2.1.0] Real-time notifications
- [2.1.0] Export functionality for reports
- [2.0.0] Complete UI redesign
- [2.0.0] Multi-language support
- [1.0.0] Initial release
- [1.0.0] Core functionalityContent-Type: text/markdown; charset=utf-8
Note: Returns 204 No Content if no changes are found.
Get changelog differences in markdown format for all versions newer than the specified version.
Parameters:
repo(string): Repository nameversion(string): Base version to compare against
Query Parameters:
title(string, optional): Custom title for the markdown output (max 128 chars, sanitized)
Response:
# New updates!
## Added
- [2.1.0] Real-time notifications
- [2.1.0] Export functionality for reports
- [2.0.0] Complete UI redesign
- [2.0.0] Multi-language support
## Changed
- [2.0.0] Database schema migration
- [2.0.0] API response format changes
## Fixed
- [2.1.0] Memory leak in data processing
- [2.1.0] UI responsiveness issues
## Removed
- [2.0.0] Legacy authentication system
- [2.0.0] Deprecated endpointsContent-Type: text/markdown; charset=utf-8
Note: Returns 204 No Content if no changes are found since the specified version.
Example with custom title:
GET /repos/my-project/since/1.0.0?title=What's%20new%20in%20v2!
Response:
# What's new in v2!
## Added
- [2.1.0] Real-time notifications
- [2.0.0] Complete UI redesignGet changelog differences in markdown format between two specific versions (inclusive).
Parameters:
repo(string): Repository nameversion1(string): First versionversion2(string): Second version
Note: Version order doesn't matter - the API will automatically determine the correct range.
Response:
# Changelog Diff: my-project (1.5.2 to 2.1.0)
## Added
- [2.1.0] Real-time notifications
- [2.1.0] Export functionality for reports
- [2.0.0] Complete UI redesign
- [2.0.0] Multi-language support
## Changed
- [2.0.0] Database schema migration
- [2.0.0] API response format changes
## Fixed
- [2.1.0] Memory leak in data processing
- [2.1.0] UI responsiveness issues
## Removed
- [2.0.0] Legacy authentication system
- [2.0.0] Deprecated endpoints
## Security
- [1.5.2] Updated authentication tokens
- [1.5.2] Enhanced input validationContent-Type: text/markdown; charset=utf-8
All endpoints return errors in the following format:
{
"success": false,
"error": "Error description",
"code": "ERROR_CODE"
}Common error codes:
REPO_NOT_CONFIGURED: Repository not found in configurationCHANGELOG_NOT_FOUND: CHANGELOG.md file not found or invalidVERSION_NOT_FOUND: Requested version doesn't existPARSE_ERROR: Error parsing changelog fileMETHOD_NOT_ALLOWED: Invalid HTTP methodENDPOINT_NOT_FOUND: Invalid API endpointIDENTICAL_VERSIONS: Cannot generate diff between identical versionsSINCE_DIFF_ERROR: Error generating diff since specified versionRANGE_DIFF_ERROR: Error generating diff between version range
This server expects CHANGELOG.md files to follow the Keep a Changelog format:
# Changelog
## [Unreleased]
### Added
- New feature for next release
### Changed
- Updated existing functionality
## [1.0.0] - 2024-01-01
### Added
- Initial release
- Core functionality
### Fixed
- Bug fixesSupported change types:
Added: New featuresChanged: Changes in existing functionalityDeprecated: Soon-to-be removed featuresRemoved: Now removed featuresFixed: Bug fixesSecurity: Vulnerability fixes
# Start development server with hot reload
bun run dev
# Start production server
bun run start
# Build the application
bun run build
# Type checking
bun run typecheck
# Run tests
bun test
# Run tests in watch mode
bun test --watchchangelogger/
├── src/
│ ├── server.ts # Main server and API routes
│ ├── parser.ts # Changelog parsing logic
│ └── types.ts # TypeScript type definitions
├── package.json # Project configuration
├── tsconfig.json # TypeScript configuration
├── .env.example # Environment template
└── README.md # This file
PORT: Server port (default: 3000)REPOS: Comma-separated list of repository folder namesREPOS_BASE_PATH: Base path for repositories (default: current directory)SQLITE_CACHE: Enable/disable SQLite caching (default: false)SQLITE_CACHE_DB_PATH: Path to SQLite cache database (default: ./cache.db)SQLITE_CACHE_TTL_HOURS: Cache TTL in hours (default: 168 = 7 days)WITH_DATES: Include release dates in markdown output (default: false)
- Ensure the repository has a
CHANGELOG.mdfile in Keep a Changelog format - Add the repository folder name to the
REPOSenvironment variable - Restart the server
The server will automatically validate and serve the new repository's changelog data.
By default, changelog entries show only version numbers:
- [2.1.0] Real-time notifications
- [2.0.0] Complete UI redesignEnable WITH_DATES=true in your .env to include release dates in a readable format:
- [2.1.0] (Apr 25, 2025) Real-time notifications
- [2.0.0] (Mar 15, 2025) Complete UI redesignDates are formatted as "MMM DD, YYYY" (e.g., "Apr 25, 2025") and only shown when available in the changelog. This feature works with all markdown endpoints (/since, /since/:version, /diff/:v1/:v2).
To keep your repositories up-to-date automatically, use the included git_pull_cron_task.sh script:
# Make the script executable (if not already)
chmod +x git_pull_cron_task.sh
# Run manually to test
./git_pull_cron_task.sh
# Set up a cron job (example: update every hour)
# Edit your crontab with: crontab -e
# Add this line to update repositories every hour:
0 * * * * /path/to/changelogger/git_pull_cron_task.sh >> /var/log/changelogger-updates.log 2>&1
# Or update every 15 minutes during business hours:
*/15 9-17 * * 1-5 /path/to/changelogger/git_pull_cron_task.sh >> /var/log/changelogger-updates.log 2>&1The script will:
- Read your
.envconfiguration to find all configured repositories - Attempt
git pullon each repository in the configured base path - Provide detailed success/failure reporting
- Exit with error code if any repositories failed to update
The server includes optional SQLite caching to significantly improve performance for repeated requests:
# Enable caching in .env
SQLITE_CACHE=true
SQLITE_CACHE_DB_PATH=./cache.db
SQLITE_CACHE_TTL_HOURS=168 # 7 daysPerformance Benefits:
- Cache Hit: ~2-3ms response time (80% improvement)
- Cache Miss: ~12-35ms (small overhead for caching)
- Cache Disabled: ~10-30ms (no change from default)
How It Works:
- Caches parsed changelog data, not the final markdown (titles remain dynamic)
- Uses file modification time for automatic cache invalidation
- Separate cache entries for different version ranges
- Automatic cleanup of expired entries (default: 7 days)
Cache Information:
The /health endpoint includes cache statistics when enabled:
{
"success": true,
"data": {
"status": "healthy",
"cache": {
"enabled": true,
"entries": 25,
"size": "64.2 KB"
}
}
}When to Enable Caching:
- ✅ High request volume (>50 req/min)
- ✅ Large changelogs (100+ versions)
- ✅ Multiple repositories
- ❌ Development/single-user scenarios
- ❌ Minimal changelog files
MIT