name: Manual Release on: workflow_dispatch: inputs: version_bump: description: Version bump type required: true default: patch type: choice options: - patch - minor - major permissions: contents: write packages: write jobs: release: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 token: ${{ secrets.GITHUB_TOKEN }} - name: Setup Node.js uses: actions/setup-node@v4 with: node-version-file: ".nvmrc" cache: npm registry-url: https://registry.npmjs.org - name: Install dependencies run: npm ci - name: Run tests and validation run: | npm run validate npm run format:check npm run lint - name: Configure Git run: | git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" - name: Bump version run: npm run version:${{ github.event.inputs.version_bump }} - name: Get new version and previous tag id: version 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: | sed -i 's/"version": ".*"/"version": "${{ steps.version.outputs.new_version }}"/' tools/installer/package.json - name: Generate web bundles run: npm run bundle - name: Package bundles for release run: | mkdir -p dist/release-bundles # Create staging directory for each platform mkdir -p dist/staging/{claude-code,chatgpt,gemini} # Collect all modules per platform cp -r src/modules/bmm/sub-modules/claude-code/* dist/staging/claude-code/ 2>/dev/null || true cp -r src/modules/bmb/sub-modules/claude-code/* dist/staging/claude-code/ 2>/dev/null || true cp -r src/modules/cis/sub-modules/claude-code/* dist/staging/claude-code/ 2>/dev/null || true cp -r src/modules/bmm/sub-modules/chatgpt/* dist/staging/chatgpt/ 2>/dev/null || true cp -r src/modules/bmb/sub-modules/chatgpt/* dist/staging/chatgpt/ 2>/dev/null || true cp -r src/modules/cis/sub-modules/chatgpt/* dist/staging/chatgpt/ 2>/dev/null || true cp -r src/modules/bmm/sub-modules/gemini/* dist/staging/gemini/ 2>/dev/null || true cp -r src/modules/bmb/sub-modules/gemini/* dist/staging/gemini/ 2>/dev/null || true cp -r src/modules/cis/sub-modules/gemini/* dist/staging/gemini/ 2>/dev/null || true # Verify bundles were copied (fail if completely empty) for platform in claude-code chatgpt gemini; do if [ ! "$(ls -A dist/staging/$platform)" ]; then echo "❌ ERROR: No bundles found for $platform" echo "This likely means 'npm run bundle' failed or bundles weren't generated" exit 1 fi echo "✅ $platform: $(find dist/staging/$platform -name '*.md' | wc -l) bundles" done # Create platform-specific archives tar -czf dist/release-bundles/bmad-bundles-claude-code-v${{ steps.version.outputs.new_version }}.tar.gz \ -C dist/staging/claude-code . tar -czf dist/release-bundles/bmad-bundles-chatgpt-v${{ steps.version.outputs.new_version }}.tar.gz \ -C dist/staging/chatgpt . tar -czf dist/release-bundles/bmad-bundles-gemini-v${{ steps.version.outputs.new_version }}.tar.gz \ -C dist/staging/gemini . # Create all-platforms archive tar -czf dist/release-bundles/bmad-bundles-all-v${{ steps.version.outputs.new_version }}.tar.gz \ -C dist/staging . - name: Commit version bump run: | 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/bmad-code-org/BMAD-METHOD/compare/${{ steps.version.outputs.previous_tag }}...v${{ steps.version.outputs.new_version }} EOF # Output for GitHub Actions echo "RELEASE_NOTES<> $GITHUB_OUTPUT cat release_notes.md >> $GITHUB_OUTPUT echo "EOF" >> $GITHUB_OUTPUT - name: Create and push tag run: | # Check if tag already exists if git rev-parse "v${{ steps.version.outputs.new_version }}" >/dev/null 2>&1; then echo "Tag v${{ steps.version.outputs.new_version }} already exists, skipping tag creation" else git tag -a "v${{ steps.version.outputs.new_version }}" -m "Release v${{ steps.version.outputs.new_version }}" git push origin "v${{ steps.version.outputs.new_version }}" fi - name: Push changes to main run: | if git push origin HEAD:main 2>/dev/null; then echo "✅ Successfully pushed to main branch" else echo "⚠️ Could not push to main (protected branch). This is expected." echo "📝 Version bump and tag were created successfully." fi - name: Publish to NPM env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} run: npm publish - name: Create GitHub Release with Bundles uses: softprops/action-gh-release@v2 with: tag_name: v${{ steps.version.outputs.new_version }} name: "BMad Method v${{ steps.version.outputs.new_version }}" body: | ${{ steps.release_notes.outputs.RELEASE_NOTES }} ## 📦 Web Bundles Download platform-specific bundles for use in AI platforms: - `bmad-bundles-claude-code-v${{ steps.version.outputs.new_version }}.tar.gz` - Claude Code / Claude Projects - `bmad-bundles-chatgpt-v${{ steps.version.outputs.new_version }}.tar.gz` - ChatGPT Custom Instructions - `bmad-bundles-gemini-v${{ steps.version.outputs.new_version }}.tar.gz` - Gemini Gems - `bmad-bundles-all-v${{ steps.version.outputs.new_version }}.tar.gz` - All platforms **Latest bundles** (bleeding edge): https://bmad-code-org.github.io/bmad-bundles/ draft: false prerelease: ${{ contains(steps.version.outputs.new_version, 'alpha') || contains(steps.version.outputs.new_version, 'beta') }} files: | dist/release-bundles/*.tar.gz - name: Summary run: | echo "## 🎉 Successfully released v${{ steps.version.outputs.new_version }}!" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "### 📦 Distribution" >> $GITHUB_STEP_SUMMARY echo "- **NPM**: Published with @latest tag" >> $GITHUB_STEP_SUMMARY echo "- **GitHub Release**: https://github.com/bmad-code-org/BMAD-METHOD/releases/tag/v${{ steps.version.outputs.new_version }}" >> $GITHUB_STEP_SUMMARY echo "- **Web Bundles**: Attached to GitHub Release (4 archives)" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "### ✅ Installation" >> $GITHUB_STEP_SUMMARY echo "\`\`\`bash" >> $GITHUB_STEP_SUMMARY echo "npx bmad-method@${{ steps.version.outputs.new_version }} install" >> $GITHUB_STEP_SUMMARY echo "\`\`\`" >> $GITHUB_STEP_SUMMARY