marcocesarato/php-conventional-changelog
Automatically generate changelogs and release notes from your Git history using Conventional Commits and SemVer. CLI tool with configurable templates and options to extract releases and output Markdown changelogs, suitable for Composer scripts and CI workflows.
Installation:
composer require --dev marcocesarato/php-conventional-changelog
Add a changelog script to your composer.json:
"scripts": {
"changelog": "conventional-changelog"
}
First Run: Generate your initial changelog (assuming no prior tags):
composer changelog --first-release
This creates a CHANGELOG.md file with all commits since the project's inception.
Daily Workflow: After committing changes following Conventional Commits, run:
composer changelog
This generates a changelog for the current release (since the last tag).
To release a patch (bug fixes) with auto-commit and tagging:
composer changelog --patch --commit
This:
composer.json (e.g., 1.0.0 → 1.0.1).v1.0.1).feat: add user authentication
fix: resolve login timeout issue
composer changelog --minor # For new features
CHANGELOG.md for accuracy.Auto-Bump and Tag:
composer changelog --commit --annotate-tag
This:
1.0.0 → 1.1.0 for a minor release).v1.1.0).Post-Release: Push the changes and tag to remote:
git push && git push --tags
Specific Version:
composer changelog --ver="2.0.0" --commit
Overrides auto-versioning (e.g., for a breaking change).
Date Range:
composer changelog --from-date="2023-01-01" --to-date="2023-06-30"
Useful for quarterly releases.
Artisan Command Integration:
Create a custom Artisan command to wrap conventional-changelog for consistency:
// app/Console/Commands/GenerateChangelog.php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Symfony\Component\Process\Process;
use Symfony\Component\Process\Exception\ProcessFailedException;
class GenerateChangelog extends Command
{
protected $signature = 'changelog:generate
{--type= : Release type (patch|minor|major)}
{--commit : Auto-commit and tag}
{--first : First release}';
protected $description = 'Generate a changelog using conventional commits';
public function handle()
{
$command = 'php vendor/bin/conventional-changelog';
if ($this->option('type')) {
$command .= " --{$this->option('type')}";
}
if ($this->option('commit')) {
$command .= ' --commit --annotate-tag';
}
if ($this->option('first')) {
$command .= ' --first-release';
}
$process = new Process(explode(' ', $command));
$process->run();
if (!$process->isSuccessful()) {
throw new ProcessFailedException($process);
}
$this->info($process->getOutput());
}
}
Register the command in app/Console/Kernel.php:
protected $commands = [
Commands\GenerateChangelog::class,
];
Now run with:
php artisan changelog:generate --minor --commit
CI/CD Pipeline: Add to your GitHub Actions or GitLab CI:
# .github/workflows/release.yml
name: Release
on:
push:
tags:
- 'v*'
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.1'
- name: Install dependencies
run: composer install -n --prefer-dist
- name: Generate changelog
run: composer changelog --commit --annotate-tag
- name: Push changes
run: |
git config --global user.name "GitHub Actions"
git config --global user.email "actions@github.com"
git push
git push --tags
Custom Configuration:
Create .changelog in your Laravel project root:
<?php
return [
'headerTitle' => 'Laravel Project Changelog',
'headerDescription' => 'All notable changes to this Laravel project will be documented here.',
'types' => [
'feat' => ['label' => '🆕 Features', 'description' => 'New features or improvements'],
'fix' => ['label' => '🐛 Bug Fixes', 'description' => 'Bug fixes and patches'],
'deprecation' => ['label' => '⚠ Deprecations', 'description' => 'Deprecated features'],
],
'ignoreTypes' => ['docs', 'style', 'refactor'],
'packageBump' => true,
'packageLockCommit' => true,
'prettyScope' => true,
'urlProtocol' => 'https',
'issueUrlFormat' => 'https://github.com/{owner}/{repo}/issues/{number}',
];
This tailors the changelog to Laravel conventions (e.g., deprecation type).
Commit Message Format:
Fixed login bug
Fix: Use fix: login button not submitting.--debug to see parsed commits:
composer changelog --debug
Version Bumping:
--commit.
Cause: composer.json or package.json is missing, or packageBump is set to false in .changelog.
Fix: Ensure the root directory contains composer.json and verify .changelog settings:
'packageBump' => true,
Tag Conflicts:
git push --tags fails due to existing tags.
Fix: Use --force or --amend:
composer changelog --amend --commit
Empty Changelog:
composer changelog produces no output.
Cause: No commits since the last tag, or all commits are ignored (e.g., docs type).
Fix: Use --history to include all commits or adjust ignoreTypes in .changelog.GPG-Signed Tags:
--sign-tag fails with gpg: no default secret key.
Fix: Configure GPG:
gpg --list-secret-keys --keyid-format LONG
gpg --export-secret-keys -a "YOUR_KEY_ID" > private.key
Then set GPG_TTY in your shell or CI:
export GPG_TTY=$(tty)
Dry Run: Test changes without committing:
composer changelog --no-tag --no-change-without-commits
Verbose Output: Enable debug mode:
composer changelog --debug
This shows parsed commits and configuration.
Manual Git Commands: If the tool behaves unexpectedly, manually inspect commits:
git log --oneline --since="20
How can I help you explore Laravel packages today?