feat: enhance manual release workflow with automatic release notes

- Add automatic release notes generation from commit history
- Categorize commits into Features, Bug Fixes, and Maintenance
- Include installation instructions and changelog links
- Add preview-release-notes script for testing
- Update GitHub release creation to use generated notes
This commit is contained in:
Brian Madison
2025-08-16 20:35:41 -05:00
parent 3f5abf347d
commit 3eb706c49a
3 changed files with 135 additions and 4 deletions

View File

@@ -51,9 +51,11 @@ jobs:
- name: Bump version
run: npm run version:${{ github.event.inputs.version_bump }}
- name: Get new version
- name: Get new version and previous tag
id: version
run: echo "new_version=$(node -p "require('./package.json').version")" >> $GITHUB_OUTPUT
run: |
echo "new_version=$(node -p "require('./package.json').version")" >> $GITHUB_OUTPUT
echo "previous_tag=$(git describe --tags --abbrev=0)" >> $GITHUB_OUTPUT
- name: Update installer package.json
run: |
@@ -67,6 +69,64 @@ jobs:
git add .
git commit -m "release: bump to v${{ steps.version.outputs.new_version }}"
- name: Generate release notes
id: release_notes
run: |
# Get commits since last tag
COMMITS=$(git log ${{ steps.version.outputs.previous_tag }}..HEAD --pretty=format:"- %s" --reverse)
# Categorize commits
FEATURES=$(echo "$COMMITS" | grep -E "^- (feat|Feature)" || true)
FIXES=$(echo "$COMMITS" | grep -E "^- (fix|Fix)" || true)
CHORES=$(echo "$COMMITS" | grep -E "^- (chore|Chore)" || true)
OTHERS=$(echo "$COMMITS" | grep -v -E "^- (feat|Feature|fix|Fix|chore|Chore|release:|Release:)" || true)
# Build release notes
cat > release_notes.md << 'EOF'
## 🚀 What's New in v${{ steps.version.outputs.new_version }}
EOF
if [ ! -z "$FEATURES" ]; then
echo "### ✨ New Features" >> release_notes.md
echo "$FEATURES" >> release_notes.md
echo "" >> release_notes.md
fi
if [ ! -z "$FIXES" ]; then
echo "### 🐛 Bug Fixes" >> release_notes.md
echo "$FIXES" >> release_notes.md
echo "" >> release_notes.md
fi
if [ ! -z "$OTHERS" ]; then
echo "### 📦 Other Changes" >> release_notes.md
echo "$OTHERS" >> release_notes.md
echo "" >> release_notes.md
fi
if [ ! -z "$CHORES" ]; then
echo "### 🔧 Maintenance" >> release_notes.md
echo "$CHORES" >> release_notes.md
echo "" >> release_notes.md
fi
cat >> release_notes.md << 'EOF'
## 📦 Installation
```bash
npx bmad-method install
```
**Full Changelog**: https://github.com/bmadcode/BMAD-METHOD/compare/${{ steps.version.outputs.previous_tag }}...v${{ steps.version.outputs.new_version }}
EOF
# Output for GitHub Actions
echo "RELEASE_NOTES<<EOF" >> $GITHUB_OUTPUT
cat release_notes.md >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
- name: Create and push tag
run: |
git tag -a "v${{ steps.version.outputs.new_version }}" -m "Release v${{ steps.version.outputs.new_version }}"
@@ -86,7 +146,8 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: v${{ steps.version.outputs.new_version }}
release_name: Release v${{ steps.version.outputs.new_version }}
release_name: "BMad Method v${{ steps.version.outputs.new_version }}"
body: ${{ steps.release_notes.outputs.RELEASE_NOTES }}
draft: false
prerelease: false
@@ -95,4 +156,7 @@ jobs:
echo "🎉 Successfully released v${{ steps.version.outputs.new_version }}!"
echo "📦 Published to NPM with @stable tag"
echo "🏷️ Git tag: v${{ steps.version.outputs.new_version }}"
echo "✅ Users running 'npx bmad-method@stable install' will now get version ${{ steps.version.outputs.new_version }}"
echo "✅ Users running 'npx bmad-method install' will now get version ${{ steps.version.outputs.new_version }}"
echo ""
echo "📝 Release notes preview:"
cat release_notes.md

View File

@@ -35,6 +35,7 @@
"lint:fix": "eslint . --ext .js,.cjs,.mjs,.yaml --fix",
"list:agents": "node tools/cli.js list:agents",
"prepare": "husky",
"preview:release": "node tools/preview-release-notes.js",
"validate": "node tools/cli.js validate",
"version:all": "node tools/bump-all-versions.js",
"version:all:major": "node tools/bump-all-versions.js major",

66
tools/preview-release-notes.js Executable file
View File

@@ -0,0 +1,66 @@
const { execSync } = require('node:child_process');
const fs = require('node:fs');
// Get the latest stable tag (exclude beta tags)
const allTags = execSync('git tag -l | sort -V', { encoding: 'utf8' }).split('\n').filter(Boolean);
const stableTags = allTags.filter((tag) => !tag.includes('beta'));
const latestTag = stableTags.at(-1) || 'v5.0.0';
// Get commits since last tag
const commits = execSync(`git log ${latestTag}..HEAD --pretty=format:"- %s" --reverse`, {
encoding: 'utf8',
})
.split('\n')
.filter(Boolean);
// Categorize commits
const features = commits.filter((commit) => /^- (feat|Feature)/.test(commit));
const fixes = commits.filter((commit) => /^- (fix|Fix)/.test(commit));
const chores = commits.filter((commit) => /^- (chore|Chore)/.test(commit));
const others = commits.filter(
(commit) => !/^- (feat|Feature|fix|Fix|chore|Chore|release:|Release:)/.test(commit),
);
// Get next version (you can modify this logic)
const currentVersion = require('../package.json').version;
const versionParts = currentVersion.split('.').map(Number);
const nextVersion = `${versionParts[0]}.${versionParts[1] + 1}.0`; // Default to minor bump
console.log(`## 🚀 What's New in v${nextVersion}\n`);
if (features.length > 0) {
console.log('### ✨ New Features');
for (const feature of features) console.log(feature);
console.log('');
}
if (fixes.length > 0) {
console.log('### 🐛 Bug Fixes');
for (const fix of fixes) console.log(fix);
console.log('');
}
if (others.length > 0) {
console.log('### 📦 Other Changes');
for (const other of others) console.log(other);
console.log('');
}
if (chores.length > 0) {
console.log('### 🔧 Maintenance');
for (const chore of chores) console.log(chore);
console.log('');
}
console.log('\n## 📦 Installation\n');
console.log('```bash');
console.log('npx bmad-method install');
console.log('```');
console.log(
`\n**Full Changelog**: https://github.com/bmadcode/BMAD-METHOD/compare/${latestTag}...v${nextVersion}`,
);
console.log(`\n---\n📊 **Summary**: ${commits.length} commits since ${latestTag}`);
console.log(`🏷️ **Previous tag**: ${latestTag}`);
console.log(`🚀 **Next version**: v${nextVersion} (estimated)`);