AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL unreviewed MIT Self-run

Changelog Generator

skill-curiouslearner-devkit-changelog-generator · by CuriousLearner

Automatically generate changelogs from git commits following conventional commits, semantic versi...

No reviews yet
0 installs
25 views
0.0% view→install

Install

$ agentstack add skill-curiouslearner-devkit-changelog-generator

Open-source listing, not yet scanned by AgentStack. Follow the source repository for install instructions.

Security review

⚠ Flagged

1 finding(s); flagged for manual review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures
  • high Dangerous shell/eval execution.

What it can access

  • Network access Used
  • Filesystem access Used
  • Shell / process execution Used
  • Environment & secrets No
  • Dynamic code execution Used

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Reliability & compatibility

Not yet reviewed
0 installs to date
no reviews yet
11mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Changelog Generator? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Changelog Generator Skill

Automatically generate changelogs from git commits following conventional commits, semantic versioning, and best practices.

Instructions

You are a changelog generation expert. When invoked:

  1. Analyze Commit History:
  • Parse git commit messages
  • Identify conventional commit types
  • Group related changes
  • Determine version bumps (major, minor, patch)
  1. Generate Changelog Entries:
  • Follow Keep a Changelog format
  • Categorize by change type
  • Include breaking changes prominently
  • Add relevant metadata (dates, versions, authors)
  1. Format Output:
  • Use markdown formatting
  • Create clear section headers
  • Add links to commits and PRs
  • Include migration guides for breaking changes
  1. Version Management:
  • Suggest semantic version numbers
  • Identify breaking changes
  • Track deprecations
  • Handle pre-release versions

Conventional Commit Types

  • feat: New feature (minor version bump)
  • fix: Bug fix (patch version bump)
  • docs: Documentation changes
  • style: Code style changes (formatting, etc.)
  • refactor: Code refactoring
  • perf: Performance improvements
  • test: Test additions or changes
  • build: Build system changes
  • ci: CI/CD changes
  • chore: Maintenance tasks
  • revert: Revert previous changes

Breaking Change: Any commit with BREAKING CHANGE: in body or ! after type (major version bump)

Usage Examples

@changelog-generator
@changelog-generator --since v1.2.0
@changelog-generator --unreleased
@changelog-generator --version 2.0.0
@changelog-generator --format keep-a-changelog
@changelog-generator --include-authors

Changelog Formats

Keep a Changelog Format

# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Added
- New feature X for improved user experience
- Support for configuration option Y

### Changed
- Updated dependency Z to version 2.0
- Improved performance of data processing

### Deprecated
- Function `oldMethod()` - use `newMethod()` instead

### Removed
- Removed deprecated API endpoint `/api/v1/old`

### Fixed
- Fixed memory leak in cache implementation
- Corrected timezone handling in date formatter

### Security
- Fixed XSS vulnerability in user input handling
- Updated crypto library to address CVE-2024-1234

## [1.5.0] - 2024-01-15

### Added
- User authentication with OAuth2
- Export functionality for reports
- Dark mode theme support

### Changed
- Redesigned dashboard UI
- Optimized database queries

### Fixed
- Fixed bug in pagination logic
- Resolved CORS issues with API

## [1.4.2] - 2024-01-10

### Fixed
- Critical bug in payment processing
- Memory leak in WebSocket connections

### Security
- Patched authentication bypass vulnerability

## [1.4.1] - 2024-01-05

### Fixed
- Hotfix for broken deployment script
- Fixed typo in error messages

## [1.4.0] - 2024-01-01

### Added
- Real-time notifications
- File upload with drag and drop
- Advanced search filters

### Changed
- Migrated from REST to GraphQL
- Updated UI components library

### Deprecated
- Old REST API endpoints (will be removed in 2.0)

[Unreleased]: https://github.com/user/repo/compare/v1.5.0...HEAD
[1.5.0]: https://github.com/user/repo/compare/v1.4.2...v1.5.0
[1.4.2]: https://github.com/user/repo/compare/v1.4.1...v1.4.2
[1.4.1]: https://github.com/user/repo/compare/v1.4.0...v1.4.1
[1.4.0]: https://github.com/user/repo/releases/tag/v1.4.0

Automated Changelog Generation

Using Git Commits

#!/bin/bash
# generate-changelog.sh - Generate changelog from git commits

VERSION=${1:-"Unreleased"}
PREV_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")

echo "# Changelog"
echo ""
echo "## [$VERSION] - $(date +%Y-%m-%d)"
echo ""

# Get commits since last tag
if [ -z "$PREV_TAG" ]; then
  COMMITS=$(git log --pretty=format:"%s|||%h|||%an" --reverse)
else
  COMMITS=$(git log ${PREV_TAG}..HEAD --pretty=format:"%s|||%h|||%an" --reverse)
fi

# Arrays for different categories
declare -a features=()
declare -a fixes=()
declare -a breaking=()
declare -a docs=()
declare -a chores=()
declare -a other=()

# Parse commits
while IFS='|||' read -r message hash author; do
  case "$message" in
    feat:*|feat\(*\):*)
      features+=("- ${message#feat*: } ([${hash}](../../commit/${hash}))")
      ;;
    fix:*|fix\(*\):*)
      fixes+=("- ${message#fix*: } ([${hash}](../../commit/${hash}))")
      ;;
    *BREAKING*|*\!:*)
      breaking+=("- ${message} ([${hash}](../../commit/${hash}))")
      ;;
    docs:*)
      docs+=("- ${message#docs: } ([${hash}](../../commit/${hash}))")
      ;;
    chore:*|build:*|ci:*)
      chores+=("- ${message#*: } ([${hash}](../../commit/${hash}))")
      ;;
    *)
      other+=("- ${message} ([${hash}](../../commit/${hash}))")
      ;;
  esac
done  0) {
    lines.push('### ⚠️ BREAKING CHANGES');
    lines.push('');
    for (const commit of breaking) {
      lines.push(`- **${commit.description}** ([${commit.hash.slice(0, 7)}](../../commit/${commit.hash}))`);
      if (commit.body) {
        const breakingNote = commit.body.match(/BREAKING CHANGE:\s*(.+)/);
        if (breakingNote) {
          lines.push(`  ${breakingNote[1]}`);
        }
      }
    }
    lines.push('');
  }

  // Other sections
  const sectionOrder = [
    'Added',
    'Changed',
    'Deprecated',
    'Removed',
    'Fixed',
    'Security',
    'Performance',
    'Documentation',
  ];

  for (const section of sectionOrder) {
    if (groups[section] && groups[section].length > 0) {
      lines.push(`### ${section}`);
      lines.push('');

      const commits = groups[section];
      const grouped = {};

      // Group by scope if present
      for (const commit of commits) {
        const key = commit.scope || '_default';
        if (!grouped[key]) grouped[key] = [];
        grouped[key].push(commit);
      }

      for (const [scope, scopeCommits] of Object.entries(grouped)) {
        if (scope !== '_default') {
          lines.push(`#### ${scope}`);
          lines.push('');
        }

        for (const commit of scopeCommits) {
          let line = `- ${commit.description}`;

          if (options.includeHash) {
            line += ` ([${commit.hash.slice(0, 7)}](../../commit/${commit.hash}))`;
          }

          if (options.includeAuthor) {
            line += ` - @${commit.author}`;
          }

          lines.push(line);
        }
      }

      lines.push('');
    }
  }

  return lines.join('\n');
}

function getLatestTag() {
  try {
    return execSync('git describe --tags --abbrev=0', { encoding: 'utf-8' }).trim();
  } catch (error) {
    return null;
  }
}

function suggestVersion(breaking, groups) {
  const latestTag = getLatestTag();
  if (!latestTag) return '1.0.0';

  const [major, minor, patch] = latestTag.replace('v', '').split('.').map(Number);

  if (breaking.length > 0) {
    return `${major + 1}.0.0`;
  }

  const hasFeatures = groups['Added'] && groups['Added'].length > 0;
  if (hasFeatures) {
    return `${major}.${minor + 1}.0`;
  }

  return `${major}.${minor}.${patch + 1}`;
}

// Main execution
function main() {
  const args = process.argv.slice(2);
  const options = {
    includeHash: !args.includes('--no-hash'),
    includeAuthor: args.includes('--author'),
    version: args.find(a => a.startsWith('--version='))?.split('=')[1],
    since: args.find(a => a.startsWith('--since='))?.split('=')[1],
  };

  const latestTag = options.since || getLatestTag();
  const commits = getCommitsSinceTag(latestTag);
  const parsed = commits.map(parseCommit);
  const { groups, breaking } = groupCommits(parsed);

  const version = options.version || suggestVersion(breaking, groups);
  const date = new Date().toISOString().split('T')[0];

  const changelog = generateMarkdown(version, date, groups, breaking, options);

  // Read existing changelog or create new
  let existingChangelog = '';
  try {
    existingChangelog = fs.readFileSync('CHANGELOG.md', 'utf-8');
  } catch (error) {
    existingChangelog = '# Changelog\n\nAll notable changes to this project will be documented in this file.\n\n';
  }

  // Insert new version after header
  const lines = existingChangelog.split('\n');
  const headerEnd = lines.findIndex(l => l.startsWith('## '));
  const newLines = [
    ...lines.slice(0, headerEnd === -1 ? lines.length : headerEnd),
    changelog,
    ...lines.slice(headerEnd === -1 ? lines.length : headerEnd),
  ];

  fs.writeFileSync('CHANGELOG.md', newLines.join('\n'));

  console.log(`✓ Generated changelog for version ${version}`);
  console.log(`  - ${commits.length} commits processed`);
  console.log(`  - ${breaking.length} breaking changes`);
  console.log(`  - Suggested version: ${version}`);
}

if (require.main === module) {
  main();
}

module.exports = { parseCommit, groupCommits, generateMarkdown };

Usage:

# Make executable
chmod +x generate-changelog.js

# Run
./generate-changelog.js

# With options
./generate-changelog.js --version=2.0.0 --author --since=v1.5.0

Python Version

#!/usr/bin/env python3
# generate_changelog.py

import re
import subprocess
from datetime import datetime
from collections import defaultdict
from typing import List, Dict, Tuple

COMMIT_PATTERN = re.compile(r'^(\w+)(\([\w-]+\))?(!)?:\s(.+)$')

TYPES = {
    'feat': {'section': 'Added', 'bump': 'minor'},
    'fix': {'section': 'Fixed', 'bump': 'patch'},
    'docs': {'section': 'Documentation', 'bump': None},
    'style': {'section': 'Style', 'bump': None},
    'refactor': {'section': 'Changed', 'bump': None},
    'perf': {'section': 'Performance', 'bump': 'patch'},
    'test': {'section': 'Tests', 'bump': None},
    'build': {'section': 'Build System', 'bump': None},
    'ci': {'section': 'CI', 'bump': None},
    'chore': {'section': 'Chores', 'bump': None},
}

def get_commits_since_tag(tag: str = None) -> List[str]:
    cmd = ['git', 'log', '--pretty=format:%H|||%s|||%b|||%an|||%ae|||%ai']
    if tag:
        cmd.insert(2, f'{tag}..HEAD')

    try:
        result = subprocess.run(cmd, capture_output=True, text=True, check=True)
        return [line for line in result.stdout.split('\n') if line]
    except subprocess.CalledProcessError:
        return []

def parse_commit(commit_line: str) -> Dict:
    parts = commit_line.split('|||')
    if len(parts)  Tuple[Dict, List]:
    groups = defaultdict(list)
    breaking = []

    for commit in commits:
        if commit['breaking']:
            breaking.append(commit)

        type_info = TYPES.get(commit['type'], {'section': 'Other Changes'})
        section = type_info['section']
        groups[section].append(commit)

    return dict(groups), breaking

def generate_markdown(version: str, groups: Dict, breaking: List) -> str:
    lines = [f"## [{version}] - {datetime.now().strftime('%Y-%m-%d')}", ""]

    if breaking:
        lines.append("### ⚠️ BREAKING CHANGES")
        lines.append("")
        for commit in breaking:
            lines.append(f"- **{commit['description']}** ([{commit['hash'][:7]}](../../commit/{commit['hash']}))")
        lines.append("")

    section_order = ['Added', 'Changed', 'Fixed', 'Security', 'Performance', 'Documentation']

    for section in section_order:
        if section in groups and groups[section]:
            lines.append(f"### {section}")
            lines.append("")
            for commit in groups[section]:
                lines.append(f"- {commit['description']} ([{commit['hash'][:7]}](../../commit/{commit['hash']}))")
            lines.append("")

    return '\n'.join(lines)

def main():
    commits = get_commits_since_tag()
    parsed = [parse_commit(c) for c in commits if parse_commit(c)]
    groups, breaking = group_commits(parsed)

    version = input("Enter version number (or press Enter for auto): ").strip() or "1.0.0"
    changelog = generate_markdown(version, groups, breaking)

    print(changelog)

    # Optionally write to file
    with open('CHANGELOG.md', 'r+') as f:
        content = f.read()
        f.seek(0, 0)
        f.write(changelog + '\n\n' + content)

if __name__ == '__main__':
    main()

GitHub Release Notes

Automated Release with Notes

# .github/workflows/release.yml
name: Release

on:
  push:
    tags:
      - 'v*'

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
        with:
          fetch-depth: 0

      - name: Generate changelog
        id: changelog
        run: |
          # Get previous tag
          PREV_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "")

          # Generate changelog
          if [ -z "$PREV_TAG" ]; then
            CHANGELOG=$(git log --pretty=format:"- %s (%h)" --reverse)
          else
            CHANGELOG=$(git log ${PREV_TAG}..HEAD --pretty=format:"- %s (%h)" --reverse)
          fi

          # Set output
          echo "changelog> $GITHUB_OUTPUT
          echo "$CHANGELOG" >> $GITHUB_OUTPUT
          echo "EOF" >> $GITHUB_OUTPUT

      - name: Create Release
        uses: actions/create-release@v1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          tag_name: ${{ github.ref }}
          release_name: Release ${{ github.ref }}
          body: |
            ## Changes in this release
            ${{ steps.changelog.outputs.changelog }}
          draft: false
          prerelease: false

Best Practices

Commit Messages

  • Use conventional commits: Enables automated changelog generation
  • Be descriptive: Clear, concise descriptions of changes
  • Include context: Why the change was made, not just what
  • Reference issues: Link to related issue numbers

Changelog Organization

  • Group by type: Features, fixes, breaking changes, etc.
  • Sort chronologically: Newest changes first
  • Include dates: Each version should have a release date
  • Link to commits: Provide links for detailed information

Version Management

  • Follow semver: Major.Minor.Patch versioning
  • Document breaking changes: Prominently display breaking changes
  • Provide migration guides: Help users upgrade
  • Track deprecations: Warn before removing features

Maintenance

  • Update regularly: Generate changelog with each release
  • Review before release: Manually verify automated output
  • Keep format consistent: Use same structure throughout
  • Archive old versions: Keep full history available

Notes

  • Always use conventional commits for automatic changelog generation
  • Include breaking changes at the top of changelog
  • Provide migration guides for major version bumps
  • Link to detailed documentation when needed
  • Keep changelog entries user-focused (not technical)
  • Review and edit generated changelogs before release
  • Use semantic versioning consistently
  • Automate changelog generation in CI/CD pipeline
  • Consider using tools like standard-version or release-please
  • Maintain changelog in git repository alongside code

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.