marcocesarato/php-conventional-changelog
Generate changelogs and release notes automatically from git history using Conventional Commits and SemVer. CLI tool (composer-friendly) outputs customizable Markdown changelog files and helps streamline versioning and releases for PHP projects.
Installation:
composer require --dev marcocesarato/php-conventional-changelog
First Run (for a new project):
php vendor/bin/conventional-changelog --first-release
This generates CHANGELOG.md with all commits since the project's inception.
Daily Workflow:
composer changelog
(Assuming you’ve added the script to composer.json as shown in the README.)
php vendor/bin/conventional-changelog --help to explore all options.docs/config.md to understand customization points.CHANGELOG.md for output formatting.Automate Release Notes:
feat: add user authentication).composer release:patch # Auto-bumps patch version, generates changelog, and commits/tags.
git push --follow-tags
composer changelog --minor # Dry-run to preview changes.
composer release:minor # Auto-bumps version, generates changelog, commits, and tags.
git push origin main --follow-tags
composer changelog --ignore-types="docs,style"
composer changelog --from-date="2023-01-01" --to-date="2023-06-30"
composer changelog --from-tag="v1.0.0" --to-tag="v2.0.0"
- name: Generate Changelog
run: composer changelog --no-verify
- name: Create Release
uses: softprops/action-gh-release@v1
if: contains(github.ref, 'tags/')
with:
generate_release_notes: false # Disable auto-notes (we use our changelog)
.changelog File:
return [
'headerTitle' => 'My Awesome Project - Release Notes',
'types' => ['feat', 'fix', 'docs'], // Only show these types
'ignorePatterns' => ['/WIP:/'], // Skip WIP commits
'packageBump' => true, // Auto-update composer.json version
'annotateTag' => true, // Use annotated tags
];
composer changelog --config=.changelog.custom
return [
'preRun' => function () {
// Run tests before generating changelog
shell_exec('php artisan test');
},
'postRun' => function () {
// Notify Slack after release
file_put_contents('release_notice.txt', 'New version released!');
},
];
Create a custom Artisan command to wrap the changelog generator:
// app/Console/Commands/GenerateChangelog.php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Symfony\Component\Process\Process;
class GenerateChangelog extends Command
{
protected $signature = 'changelog:generate
{--minor|major|patch=patch : Release type}
{--commit : Auto-commit changes}
{--no-verify : Bypass hooks}';
public function handle()
{
$process = new Process([
'php', 'vendor/bin/conventional-changelog',
$this->option('minor') ? '--minor' : '',
$this->option('patch') ? '--patch' : '',
$this->option('commit') ? '--commit' : '',
$this->option('no-verify') ? '--no-verify' : '',
]);
$process->run();
$this->output->write($process->getOutput());
}
}
Usage:
php artisan changelog:generate --minor --commit
composer.json:
Ensure packageBump: true in .changelog to update the version in composer.json during releases.'postRun' => function () {
shell_exec('npm run prod && php artisan vendor:publish --tag=public');
},
public function showReleaseNotes()
{
$changelog = file_get_contents(base_path('CHANGELOG.md'));
$latestVersion = preg_match('/## \[\d+\.\d+\.\d+\]/', $changelog, $matches)
? $matches[0] : 'Unreleased';
return view('admin.release-notes', compact('changelog', 'latestVersion'));
}
commit-msg hook to enforce Conventional Commits:
# .git/hooks/commit-msg
#!/bin/sh
php vendor/bin/conventional-changelog --no-verify --dry-run | grep -q "is not a Conventional Commit"
if [ $? -eq 0 ]; then
echo "❌ Commit message must follow Conventional Commits."
exit 1
fi
Git History Corruption:
--history on a project with a corrupted or non-linear git history (e.g., rebased commits) may produce incorrect changelogs.--merged to only include commits reachable from HEAD:
composer changelog --history --merged
Version Bump Conflicts:
composer.json is manually edited, packageBump may overwrite changes or cause merge conflicts.composer.json after running the command or use --no-tag to skip version bumping.Case-Sensitive Tag Prefixes:
v) are case-sensitive. v1.0.0 ≠ V1.0.0..changelog:
'tagPrefix' => 'v',
GPG-Signed Tags Failures:
--sign-tag may fail if GPG is not configured or the key is not available.gpg --list-secret-keys --keyid-format LONG
Composer Lock File Conflicts:
packageLockCommit: true may cause conflicts if composer.lock is edited manually.--no-tag to skip committing locks.Date Range Quirks:
--from-date/--to-date may include commits outside the intended range if the repo has a non-standard commit date format.--from-tag/--to-tag for more reliable ranges.Conventional Commits Parsing Errors:
! for breaking changes) may not parse correctly.composer changelog --dry-run
How can I help you explore Laravel packages today?