Skip to main content

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.

InputTypeDescription
versionstringRelease tag, e.g. v7.2.26

Required Secrets​

SecretPurpose
OPENROUTER_API_KEYAuthenticates the release-notes generation call
SLACK_WEBHOOK_URLIncoming webhook for the Slack notification
MARVIN_GH_PATPAT used to check out, create the release, and push docs commits to main

Optional Variables​

VariablePurpose
OPENROUTER_MODELOverrides 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 (via gh pr list --search "merged:>=<tag_date>")
  • docs_diff — diff stat and content of docs-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.