Reusable workflow for generating CHANGELOG.md using AI. Uses OpenRouter API (GPT-4o by default) to analyze commits and generate human-readable, categorized changelogs.
- AI-powered changelog generation: Uses OpenRouter API (GPT-4o) for intelligent commit analysis
- Consolidated changelog: Single CHANGELOG.md with sections per app (no overwrites)
- Monorepo support: Automatic detection of changed components via filter_paths
- GitHub Release integration: Automatically updates release notes per app tag
- GPG signing: Signed commits for changelog PRs
- Tag-based versioning: Handles between-tags, first-tag, and no-tags scenarios
- Automatic PR creation: Creates and optionally auto-merges changelog PRs
- Slack notifications: Automatic success/failure notifications
When using GPT Changelog, you must disable the @semantic-release/changelog plugin in your .releaserc.yml to avoid conflicts:
# .releaserc.yml
plugins:
- "@semantic-release/commit-analyzer"
- "@semantic-release/release-notes-generator"
# Changelog disabled - using GPT Changelog instead
# - "@semantic-release/changelog"
- - "@semantic-release/github"
- successComment: "🎉 This PR is included in version ${nextRelease.gitTag}"If both are enabled, you'll get duplicate or conflicting changelog entries.
Trigger changelog generation after your Release workflow completes on main. This is the recommended approach because it:
- Avoids race conditions (only runs once after release completes)
- Ensures the release tag exists before generating changelog
- Prevents duplicate workflow runs
name: GPT Changelog
on:
workflow_run:
workflows: ["Release"]
types: [completed]
branches: [main]
workflow_dispatch:
permissions:
contents: write
pull-requests: write
jobs:
changelog:
if: github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success'
uses: LerianStudio/github-actions-shared-workflows/.github/workflows/gptchangelog.yml@v1.0.0
with:
runner_type: "blacksmith-4vcpu-ubuntu-2404"
secrets: inheritNote: By default,
stable_releases_only: truemeans changelog is only generated for stable releases (v1.0.0), not prereleases (v1.0.0-beta.1).
Warning: Using
push: tagscan cause race conditions if your release workflow also triggers on tags. Both workflows may run simultaneously, causing duplicate runs or upload conflicts. Preferworkflow_runtrigger above.
name: Generate Changelog
on:
push:
tags:
- 'v*'
permissions:
contents: write
pull-requests: write
jobs:
changelog:
uses: LerianStudio/github-actions-shared-workflows/.github/workflows/gptchangelog.yml@v1.0.0
with:
runner_type: "blacksmith-4vcpu-ubuntu-2404"
secrets: inheritOutput:
# Changelog
## [2025-12-12]
### my-app v1.2.0
#### ✨ Features
- Added new authentication flow
- Implemented caching layer
#### 🛠 Fixes
- Fixed memory leak in worker process
---Works with any directory structure (Helm charts, microservices, packages, etc.):
name: Generate Changelog
on:
push:
tags:
- '**-v*' # Matches: agent-v1.0.0, midaz-v2.1.0, etc.
permissions:
contents: write
pull-requests: write
jobs:
changelog:
uses: LerianStudio/github-actions-shared-workflows/.github/workflows/gptchangelog.yml@v1.0.0
with:
runner_type: "blacksmith"
filter_paths: |-
charts/agent
charts/control-plane
charts/midaz
charts/reporter
path_level: '2'
secrets: inheritOutput (when multiple apps change):
# Changelog
## [2025-12-12]
### agent v1.2.0
#### ✨ Features
- Added new metric collection endpoint
#### 🛠 Fixes
- Fixed reconnection logic
### midaz v2.1.0
#### ✨ Features
- New transaction batching API
#### 🚀 Improvements
- Optimized database queries
### control-plane v1.5.0
#### 🛠 Fixes
- Fixed race condition in scheduler
---Key Benefit: All apps are consolidated into ONE CHANGELOG.md - no more overwrites when multiple apps change!
name: Release Pipeline
on:
push:
branches:
- main
jobs:
release:
uses: LerianStudio/github-actions-shared-workflows/.github/workflows/release.yml@v1.0.0
secrets: inherit
changelog:
needs: release
uses: LerianStudio/github-actions-shared-workflows/.github/workflows/gptchangelog.yml@v1.0.0
with:
runner_type: "blacksmith"
secrets: inherit| Input | Type | Default | Description |
|---|---|---|---|
runner_type |
string | blacksmith |
GitHub runner type |
filter_paths |
string | '' |
Newline-separated list of path prefixes. If empty, single-app mode |
path_level |
string | 2 |
Directory depth for app name extraction |
stable_releases_only |
boolean | true |
Only generate changelogs for stable releases (skip beta/rc/alpha) |
openai_model |
string | openai/gpt-4o |
OpenRouter model for changelog generation |
max_context_tokens |
string | 80000 |
Maximum context tokens for API |
All secrets are inherited via secrets: inherit. Required secrets in your repository:
| Secret | Description |
|---|---|
OPENROUTER_API_KEY |
OpenRouter API key for AI model access |
LERIAN_STUDIO_MIDAZ_PUSH_BOT_APP_ID |
GitHub App ID for authentication |
LERIAN_STUDIO_MIDAZ_PUSH_BOT_PRIVATE_KEY |
GitHub App private key |
LERIAN_CI_CD_USER_GPG_KEY |
GPG private key for signing commits |
LERIAN_CI_CD_USER_GPG_KEY_PASSWORD |
GPG key passphrase |
LERIAN_CI_CD_USER_NAME |
Git committer name |
LERIAN_CI_CD_USER_EMAIL |
Git committer email |
SLACK_WEBHOOK_URL |
(Optional) Slack webhook for notifications |
Unlike traditional matrix-based approaches where each app generates its own changelog (causing overwrites), this workflow uses a single-job consolidated approach:
- Detect all changed apps via
changed-pathsaction - Single job iterates through all changed apps
- Accumulates changelog entries per app into one consolidated file
- Creates one PR with all changes
Result: One CHANGELOG.md at repo root with sections for each app that changed.
The workflow automatically determines the commit range for changelog generation:
| Scenario | Range | Example |
|---|---|---|
| Two or more tags | Previous tag → Current tag | v1.0.0...v1.1.0 |
| First tag | First commit → Current tag | abc123...v1.0.0 |
| No tags | First commit → HEAD | abc123...HEAD |
For monorepos, the workflow supports app-specific tags:
| App | Tag Pattern | Example |
|---|---|---|
| agent | agent-v* |
agent-v1.0.0 |
| control-plane | control-plane-v* |
control-plane-v2.1.0 |
This works with any directory structure:
apps/api,apps/worker→ tags:api-v1.0.0,worker-v2.0.0services/auth,services/billing→ tags:auth-v1.0.0,billing-v1.5.0charts/midaz,charts/agent→ tags:midaz-v1.0.0,agent-v2.0.0
GPTChangelog organizes commits into these categories:
- ✨ Features: New features added
- 🛠 Fixes: Bug fixes and improvements
- 📚 Documentation: Documentation updates
- 🚀 Improvements: Performance or backend optimizations
⚠️ Breaking Changes: Breaking changes- 🙌 Contributors: Acknowledgments
- Detects changed paths (monorepo) or sets single-app mode
- Outputs matrix for changelog generation job
- Installs gptchangelog and dependencies
- Iterates through all changed apps in a single job
- Generates consolidated CHANGELOG.md with sections per app
- Updates GitHub Release for each app's tag
- Creates PR with changelog update (GPG-signed)
- Auto-merges PR if possible
- Sends Slack notification on completion
- Skipped if
SLACK_WEBHOOK_URLnot configured
Run changelog generation after the release workflow:
changelog:
needs: release
uses: LerianStudio/github-actions-shared-workflows/.github/workflows/gptchangelog.yml@v1.0.0
secrets: inheritGPTChangelog works best with conventional commits:
feat:- New featuresfix:- Bug fixesdocs:- Documentationperf:- Performance improvements
Add SLACK_WEBHOOK_URL secret for team notifications.
Issue: Workflow runs but no CHANGELOG.md is created
Solutions:
- Check OpenRouter API key is valid (
OPENROUTER_API_KEY) - Verify tag format matches expected pattern
- Check if there are commits in the version range
- Review workflow logs for gptchangelog errors
Issue: CHANGELOG shows wrong version
Solutions:
- Verify tag format (should include version number)
- Check sed command output in logs
- Ensure CHANGELOG has standard version header format
Issue: Changelog generated but PR fails
Solutions:
- Verify GitHub App has
contents: writeandpull-requests: writepermissions - Check if branch already exists
- Review PR creation step logs
Issue: Changelog generation fails with API errors
Solutions:
- Verify
OPENROUTER_API_KEYis set correctly - Check API rate limits
- Try reducing
max_context_tokens - Ensure model name is valid (e.g.,
openai/gpt-4o)
Issue: No apps in matrix for monorepo
Solutions:
- Verify
filter_pathsmatches your directory structure - Check
path_levelis correct - Ensure changes are in tracked paths
- Review changed-paths action output
name: Changelog
on:
push:
tags: ['v*']
jobs:
changelog:
uses: LerianStudio/github-actions-shared-workflows/.github/workflows/gptchangelog.yml@v1.0.0
secrets: inheritname: Changelog
on:
push:
tags: ['**-v*']
jobs:
changelog:
uses: LerianStudio/github-actions-shared-workflows/.github/workflows/gptchangelog.yml@v1.0.0
with:
filter_paths: |-
charts/agent
charts/control-plane
charts/midaz
charts/reporter
path_level: '2'
secrets: inheritname: Changelog
on:
push:
tags: ['**-v*']
jobs:
changelog:
uses: LerianStudio/github-actions-shared-workflows/.github/workflows/gptchangelog.yml@v1.0.0
with:
filter_paths: |-
services/api
services/worker
services/scheduler
path_level: '2'
secrets: inheritchangelog:
uses: LerianStudio/github-actions-shared-workflows/.github/workflows/gptchangelog.yml@v1.0.0
with:
openai_model: 'anthropic/claude-3.5-sonnet'
max_context_tokens: '128000'
secrets: inherit- Release - Create releases that trigger changelog generation
- Build - Build Docker images after release
- Slack Notify - Notification system