Skip to content

Improve release workflow with version validation and grouped changelog #24

@gregpriday

Description

@gregpriday

Summary

Enhance the GitHub release workflow to prevent version skew, generate better changelogs grouped by conventional commit types, and improve the release process ergonomics.

Problem Statement

Current release workflow limitations:

  • No validation that git tag matches package.json version
  • Version mismatches can cause confusion and publishing issues
  • Generated changelog is flat list without categorization
  • No grouping by feature/fix/chore
  • Missing changelog formatting makes releases hard to scan
  • No automated check for uncommitted version bumps

This affects:

  • Release reliability and consistency
  • Changelog readability for users
  • Developer experience during releases
  • NPM package version accuracy

Current State

Existing Workflow:

  • .github/workflows/release.yml - Triggered on version tags
  • Quality checks run before publish (lint, format, tests)
  • Publishes to NPM on tag push
  • Creates GitHub release with generated changelog
  • Uses simple git log format: git log --pretty=format:"- %s (%h)"

Version Management:

Missing:

  • Version tag validation against package.json
  • Conventional commit parsing for changelog
  • Categorized changelog sections (Features, Fixes, etc.)
  • Breaking change detection
  • Pre-release tag handling

Proposed Solution

1. Version Validation Script

Create scripts/validate-version.sh:

#!/bin/bash
# Extract version from tag (e.g., v0.13.1 -> 0.13.1)
TAG_VERSION=${GITHUB_REF#refs/tags/v}
# Extract version from package.json
PKG_VERSION=$(node -p "require('./package.json').version")

if [ "$TAG_VERSION" != "$PKG_VERSION" ]; then
  echo "Error: Tag version ($TAG_VERSION) doesn't match package.json ($PKG_VERSION)"
  exit 1
fi

2. Enhanced Changelog Generation

Use conventional commit parsing:

# Group commits by type
FEATURES=$(git log $PREV_TAG..HEAD --grep="^feat" --pretty=format:"- %s (%h)")
FIXES=$(git log $PREV_TAG..HEAD --grep="^fix" --pretty=format:"- %s (%h)")
DOCS=$(git log $PREV_TAG..HEAD --grep="^docs" --pretty=format:"- %s (%h)")
CHORE=$(git log $PREV_TAG..HEAD --grep="^chore" --pretty=format:"- %s (%h)")
BREAKING=$(git log $PREV_TAG..HEAD --grep="BREAKING CHANGE" --pretty=format:"- %s (%h)")

Output format:

## 🚀 Features
- Add CSV export to analytics dashboard (abc123)
- Support dark mode across all pages (def456)

## 🐛 Bug Fixes
- Fix authentication timeout after 30 minutes (ghi789)
- Resolve memory leak in file processor (jkl012)

## 📚 Documentation
- Update deployment guide for Docker (mno345)

## 🔧 Maintenance
- Upgrade React to version 19 (pqr678)

## ⚠️ Breaking Changes
- Remove deprecated API endpoints (stu901)

3. Pre-release Tag Detection

Handle alpha/beta/rc tags differently:

  • Mark as pre-release in GitHub
  • Skip NPM publish for pre-releases (or use --tag next)
  • Different changelog formatting

Affected Components

Implementation Approach

Phase 1: Version Validation

  1. Create validation script in scripts/
  2. Add validation step to release workflow (before publish)
  3. Test with intentional mismatch

Phase 2: Enhanced Changelog

  1. Update changelog generation in workflow
  2. Group by conventional commit type
  3. Add emoji icons for visual scanning
  4. Detect breaking changes section

Phase 3: Documentation

  1. Document release process in CONTRIBUTING.md
  2. Explain version tagging workflow
  3. Document conventional commit expectations

Tasks

  • Create scripts/validate-version.sh with tag validation logic
  • Make script executable: chmod +x scripts/validate-version.sh
  • Add version validation step to .github/workflows/release.yml before npm publish
  • Update changelog generation to parse conventional commits
  • Add grouping by type: feat, fix, docs, chore, refactor, test, style
  • Add "Breaking Changes" section detection
  • Add emoji prefixes for visual categorization (🚀 🐛 📚 🔧 ⚠️)
  • Handle empty sections (don't show if no commits)
  • Add pre-release detection for alpha/beta/rc tags
  • Mark pre-releases appropriately in GitHub
  • Update CHANGELOG.md template
  • Create/update CONTRIBUTING.md with release process documentation
  • Document conventional commit expectations
  • Add release checklist to documentation
  • Test workflow with dry-run release
  • Add failure examples to CI (test with mismatched versions)

Acceptance Criteria

  • CI fails if git tag version ≠ package.json version
  • Clear error message explains version mismatch
  • Generated changelog is grouped by conventional commit types
  • Breaking changes prominently displayed in separate section
  • Empty sections don't appear in changelog
  • Pre-release tags (alpha, beta, rc) handled correctly
  • Documentation explains release workflow
  • Release notes are more readable and scannable
  • No manual changelog editing required
  • All releases after this change use the new format

Additional Context

Conventional Commit Types:

  • feat: - New features (🚀)
  • fix: - Bug fixes (🐛)
  • docs: - Documentation changes (📚)
  • chore: - Maintenance tasks (🔧)
  • refactor: - Code restructuring (♻️)
  • test: - Test additions/changes (✅)
  • style: - Formatting changes (💅)
  • perf: - Performance improvements (⚡)

Example Release Notes (Current):

- Added E2E tests (abc123)
- Fixed memory leak (def456)
- Updated README (ghi789)
- Bumped dependencies (jkl012)

Example Release Notes (Proposed):

## 🚀 Features
- Add E2E golden file tests for all formats (abc123)

## 🐛 Bug Fixes
- Fix memory leak in transformer pipeline (def456)

## 📚 Documentation
- Update README with new CLI flags (ghi789)

## 🔧 Maintenance
- Bump dependencies to latest versions (jkl012)

References:

Similar Projects with Good Release Workflows:

Metadata

Metadata

Assignees

No one assigned

    Labels

    priority-3 🌿Low impact polish/minor bugs/chores. Backlog if capacity allows.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions