Release Changelog & Notifications
cm-admin automates release notes generation, changelog docs updates, and Slack notifications as part of the gem release process. When a release is published, an AI-generated summary of the changes is posted to the docs site and to Slack — no manual changelog writing required.
How It Works
release-cm-gem.yml (manual dispatch)
└─ build & push gem
└─ changelog-release.yml (reusable workflow)
├─ collect_context.sh → gathers git log, PR bodies, docs diff
├─ generate_release_notes.rb → calls OpenRouter, returns structured JSON
├─ Create GitHub Release → tag + AI-generated body
├─ update_docs_page.sh → prepends entry to monthly changelog page
├─ update_release_registry.rb→ updates docs-site/static/releases.json
├─ Commit & push to main → docs changes
└─ notify_slack_release.rb → rich Slack notification
Workflow: changelog-release.yml
A reusable workflow (workflow_call) invoked by release-cm-gem.yml after the gem is pushed. It receives the release version as input.
| Input | Type | Description |
|---|---|---|
version | string | Release tag, e.g. v7.2.26 |
Required Secrets
| Secret | Purpose |
|---|---|
OPENROUTER_API_KEY | Authenticates the release-notes generation call |
SLACK_WEBHOOK_URL | Incoming webhook for the Slack notification |
MARVIN_GH_PAT | PAT used to check out, create the release, and push docs commits to main |
Optional Variables
| Variable | Purpose |
|---|---|
OPENROUTER_MODEL | Overrides the default model (openai/gpt-6-luna) |
Components
collect_context.sh
Gathers everything the AI needs into /tmp/release-context/:
git_log— commits since the previous tag (up to 50)pr_bodies— merged PR titles and bodies since the previous tag's commit date (viagh pr list --search "merged:>=<tag_date>")docs_diff— diff stat and content ofdocs-site/changes since the previous tag
generate_release_notes.rb
Sends the collected context to OpenRouter with a strict JSON schema (response_format) and prints the result to stdout:
{
"docs_markdown": "...", // full changelog page content
"slack_highlights": "...", // 1-2 sentence paragraph for the ✨ Highlights section
"slack_details": ["..."], // bullet items for the 📋 Details section
"warning": "..." | null, // breaking-change warning, if any
"migration_commands": ["..."] | null
}
If OPENROUTER_API_KEY is unset or the API call fails, the script falls back to raw git-log output so the release never blocks on AI availability.
update_docs_page.sh
Prepends a ## <version> (<date>) section to the current month's changelog page at docs-site/docs/Changelog/<YYYY-MM>.md. If the file doesn't exist yet, it creates it with frontmatter (sidebar_position derived from the year-month) and a # Release Notes — <Month Year> header.
update_release_registry.rb
Appends release metadata to docs-site/static/releases.json:
{
"version": "7.2.26",
"date": "2026-09-07",
"has_breaking_changes": false,
"has_migrations": false,
"docs_url": "https://docs.cm-admin.commutatus.com/docs/Changelog/2026-09"
}
Entries are deduplicated by version and sorted with Gem::Version semantics.
notify_slack_release.rb
Posts a Block Kit message to the Slack webhook containing:
- Header with the version
- ✨ Highlights paragraph summarizing the release
- ⚠️ Breaking Changes block (shows a "✅ No breaking changes" fallback when there are none)
- 📋 Details bullets with emoji and PR links
- Buttons linking to the GitHub release and the changelog docs page
- Context footer with the release date
Prompt Template
The AI prompt lives at .github/prompts/prompt_template.txt. It instructs the model to produce categorized release notes (🚀 Features, 🐛 Bug Fixes, ✨ Improvements, ⚠️ Breaking Changes, 📚 Documentation) plus Slack content: a highlights paragraph, detail bullets with PR links, and breaking-change/migration info. The Slack Blocks themselves are built by notify_slack_release.rb. Edit this file to tune the tone or structure of generated notes.
Changelog Docs
Generated pages live under docs-site/docs/Changelog/, one file per month (2026-09.md), with an index.md landing page. Each release prepends its section, so the newest release appears first within a month.