Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Php Conventional Changelog Laravel Package

marcocesarato/php-conventional-changelog

Automatically generate changelogs and release notes from your Git commit history using Conventional Commits and SemVer. Configurable, Composer-friendly, and easy to run from the terminal for streamlined releases.

View on GitHub
Deep Wiki
Context7

Getting Started

Install as a dev dependency (never ship it in production):

composer require --dev marcocesarato/php-conventional-changelog

Requires PHP >= 7.1.3 and git >= 2.1.4 — the PHP constraint applies to the tool, not your app.

Add composer scripts so the whole team uses the same entry points:

"scripts": {
  "changelog": "conventional-changelog",
  "release": "conventional-changelog --commit",
  "release:patch": "conventional-changelog --patch --commit",
  "release:minor": "conventional-changelog --minor --commit",
  "release:major": "conventional-changelog --major --commit"
}

First use case — bootstrap an existing repo once:

php vendor/bin/conventional-changelog --history

--history rebuilds the entire changelog from all releases. Warning: it overwrites CHANGELOG.md, so run it once deliberately and commit the result. For a brand-new/unreleased project, use --first-release instead (defaults to 1.0.0 unless you pass --ver).

Where to look first:

  1. php vendor/bin/conventional-changelog --help — the CLI is the source of truth for flags.
  2. docs/config.md in the vendor package — the full .changelog schema.
  3. The package's own CHANGELOG.md — a live example of the output shape.

Day-to-day loop is just:

composer release:minor   # or patch/major — generates changelog, commits, tags

The tool reads commits since the last tag, parses conventional commit types, bumps the semver version (!/BREAKING CHANGE → MAJOR, feat → MINOR, everything else → PATCH), writes CHANGELOG.md, commits, and creates a tag.

Implementation Patterns

Enforce conventional commits before the tool ever runs. The generator can only group what it can parse. Add a commit-msg hook (Husky, CaptainHook, or a simple shell hook) that rejects messages not matching type(scope): subject. Without this, malformed commits silently disappear from the changelog or land in an "uncategorized" bucket.

Prefer squash-merge with a conventional PR title. The squash commit message becomes the changelog entry, so one well-formed PR title = one clean line in the release notes. This is the lowest-friction way to keep history parseable on a team.

Split "generate" from "release". During feature work, run composer changelog (no --commit) to preview CHANGELOG.md and confirm grouping/bump level. Only run composer release:* when you actually intend to commit and tag. This gives you a free dry-run.

Pin the bump level explicitly in CI/release branches. Auto-detection is convenient but a stray feat on a hotfix branch will bump MINOR. Use --patch / --minor / --major to force intent.

Use --ver for hand-managed version numbers (e.g. coordinating with an app version or a prerelease train):

php vendor/bin/conventional-changelog --ver="2.0.1" --commit

Prerelease trains are handled with --rc, --beta, --alpha, which append the suffix to the bumped version. Keep prerelease tags on a dedicated branch so final-release bumps compute from the right base.

Regenerate a specific historical release without touching the rest of the file:

php vendor/bin/conventional-changelog --from-tag="v1.0.2" --to-tag="1.0.4"
php vendor/bin/conventional-changelog --from-date="2020-12-01" --to-date="2021-01-01"

Useful for backfilling releases that were published by hand or before the tool was adopted.

Configure once via .changelog in the repo root (or point at it with --config). It returns a PHP array merged over the defaults — omit keys you don't care about:

return [
    'types' => ['feat', 'fix', 'perf', 'refactor'], // whitelist shown in the changelog
    'ignoreTypes' => ['chore', 'ci', 'docs', 'style', 'test', 'build'],
    'annotateTag' => true,
    'signTag' => false,
];

Defaults already ignore build, chore, ci, docs, perf, refactor, revert, style, test. To include all types, set both types and ignoreTypes to empty arrays.

Annotated / signed tags for supply-chain hygiene:

php vendor/bin/conventional-changelog --commit --annotate-tag="Release version"
php vendor/bin/conventional-changelog --commit --sign-tag

--sign-tag implies annotated — don't combine both flags.

Wire the tag, not the changelog, into your pipeline. Let the tool commit + tag locally (or in a release job), push with git push --follow-tags, and have CD trigger on the tag. The changelog file is a byproduct; the tag is the release event.

--commit-all vs --commit: --commit commits the changelog artifacts, --commit-all stages everything in the working tree. In a release job, ensure the working tree is otherwise clean and prefer the narrower --commit so you don't sweep in unrelated files.

Amending instead of stacking: --amend folds the changelog into the current HEAD commit — handy on a release PR branch where you want one commit before merge.

Gotchas and Tips

Shallow clones break tag discovery. This is the #1 CI failure. The tool diffs "since last tag"; with actions/checkout defaults (fetch-depth: 1) no tags exist, so it treats everything as new or produces wrong ranges. Set fetch-depth: 0 (or git fetch --tags --unshallow) before running.

--history is destructive to CHANGELOG.md. It rewrites the whole file. Never run it in an automated job; use it once at adoption and review the diff by hand.

Detached HEAD / read-only CI tokens can't tag. --commit performs a real git commit and git tag. Run releases on a checkout with write access and a configured user identity (user.name, user.email), or run locally and push tags. If you must skip tagging, use --no-tag.

Unparseable commits vanish silently. Non-conventional messages are excluded, not flagged. If a release's changelog looks thin, inspect git log <lastTag>..HEAD --oneline — the missing entries are almost always malformed subjects. --no-change-without-commits exists to avoid writing an empty release when nothing parseable is found.

Squash merges can erase the type prefix if your merge tool rewrites the subject (e.g. strips feat:). Verify a merge's resulting commit message before trusting the next changelog.

Merge noise: --merged restricts to commits whose tips are reachable from HEAD, filtering out abandoned branch commits that otherwise pollute the range.

Hooks fight the release commit. Repos with pre-commit/commit-msg hooks (linters, PHPStan) will run during the tool's internal commit and can fail or reformat files mid-release. --no-verify bypasses both hooks for that commit — use it deliberately in release jobs.

--first-release doesn't imply "look at all history". It anchors version 1.0.0; older commits aren't backfilled. If you want the full past, use --history. These are different jobs.

.changelog returns PHP, so a syntax error manifests as a confusing failure rather than a config message. If options are being ignored, php -l .changelog first. Also confirm the file is at the working directory root or passed via --config — the tool resolves it relative to the working dir, not the package path (the positional path argument changes where output goes).

Config is merged, not replaced. Removing a line doesn't remove the default — the default ignored types still apply. To opt out, explicitly set the key to [].

Commit links come from repo metadata (git remote / composer info). In a mirrored or fork-based workflow, verify the generated links point where you expect before publishing release notes.

Scopes and non-ASCII descriptions have historically caused grouping/formatting bugs (fixed in 1.17.x). Keep scopes simple (api, auth, cli) — avoid spaces and punctuation — and pin a recent version (^1.17) if you have non-Latin commit messages.

Version pinning matters for Symfony compatibility. Recent releases added Symfony 7 and 8 support; on an older Symfony-based app, allow the constraint to resolve rather than hard-pinning, or you'll hit the console version mismatch that 1.17.1 patched.

License note: GPL-3.0. As a dev-only tool that never ships in your vendor/ production bundle it's normally fine, but it's a policy check worth raising with legal for closed-source products before making it a required part of the release pipeline.

Debugging a bad bump: run without --commit, read the generated CHANGELOG.md, and git describe --tags --abbrev=0 to confirm the "last tag" the tool is diffing from. Most versioning surprises trace back to a missing/incorrect tag or a commit type the whitelist excludes.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums
rlacerda83/query-parser
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings