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

Laravel Changelog Laravel Package

markwalet/laravel-changelog

A Laravel package for managing and displaying your application's changelog. Keep releases and their changes in a simple, version-controlled file, then read them through a clean facade to surface version history in your UI, API, or docs. Lightweight and easy to configure—no database required.

View on GitHub
Deep Wiki
Context7

Getting Started

markwalet/laravel-changelog gives you an Artisan- and facade-driven workflow for maintaining a CHANGELOG.md (Keep a Changelog style) inside a Laravel app, so release notes are written as you ship rather than reconstructed from git log at release time.

Requirements as of v1.13.0: PHP 8.2+ and Laravel 12+. Laravel 10 and 11 support was removed in this release — if you are still on either, stay on the previous minor or finish the framework upgrade first.

Install and publish the config:

composer require markwalet/laravel-changelog
php artisan vendor:publish --tag=changelog-config

Then look at, in this order:

  1. config/changelog.php — the list of changelog files, the default file, the change types (Added / Changed / Deprecated / Removed / Fixed / Security) and the format/driver.
  2. php artisan list changelog — enumerate the actual command signatures for your installed version before wiring anything into scripts; names and arguments have shifted between minors.
  3. The facade Markwalet\Changelog\Facades\Changelog — this is the programmatic surface (unreleased(), released(), versions(), release(...)), and everything the commands do is reachable here.

First use case — record a change without touching Markdown by hand, then promote it at release:

php artisan changelog:add added "Add invoice PDF export"
php artisan changelog:add fixed "Correct rounding on multi-currency totals"
php artisan changelog:release 1.13.0

The release step moves the pending entries out of the unreleased bucket into a dated version section, leaving a fresh, empty unreleased section behind for the next cycle.

Implementation Patterns

Write entries in the PR that ships the change. The package's value is only realised when the changelog entry is part of the same commit as the feature. Enforce it with a checklist item in your PR template and a reviewer habit, or add a lightweight CI check that fails a PR touching app/ without touching the changelog.

Two-file model (recommended for libraries + apps). If you also maintain a user-facing changelog separate from an internal one, register both files in config/changelog.php and pass the file argument explicitly on every command. Avoid relying on the default file in scripts — an implicit default is a silent footgun when someone reorders the config array.

Drive the release from your deploy pipeline. A typical release job:

php artisan changelog:release "${RELEASE_VERSION}" || exit 1
git add CHANGELOG.md changelog/
git commit -m "Release ${RELEASE_VERSION}"

Because v1.13.0 makes commands return explicit integer success/failure status codes, set -e, && chains and if php artisan changelog:release ...; then now behave correctly. Prior to this release, failures could be masked by an exit code of 0 — if you had a manual "did it actually write?" check in your pipeline, remove it.

Programmatic entries from application code. For user-visible product changelogs (e.g. an in-app "What's new" panel), write from a listener or a scheduled command rather than the CLI:

use Markwalet\Changelog\Facades\Changelog;

Changelog::unreleased()->add(new Added('Add invoice PDF export'));

Reading back is symmetrical — Changelog::released() yields release objects you can map into an API resource or a Blade partial, keeping the in-app changelog and the repo file from drifting apart.

Test-time assertions. Bind the package's adapter in your test container and assert on the changelog in feature tests (e.g. "shipping a refund emits a Fixed entry"). This keeps the taxonomy honest — nothing rots faster than a changelog where half the fixes are filed under "Changed".

Tag-driven versions. Keep changelog:release <version> and git tag <version> adjacent in the same job, and derive the version from a single variable. Divergence between the file's latest heading and the pushed tag is the most common failure mode of changelog tooling.

Format choice. Markdown is the pragmatic default for anything a human reads. Only reach for the XML/structured driver if a downstream consumer parses it — and see the gotchas below.

Gotchas and Tips

The unreleased .gitkeep placeholder must be committed. v1.13.0 restored this placeholder. Because the unreleased entries live in a directory that can legitimately be empty, a missing .gitkeep means a clean checkout has no unreleased directory at all, and the next changelog:add may fail or silently create a different layout. Ensure .gitkeep is not caught by a broad *.gitkeep-unaware .gitignore, and re-commit it if an older release stripped it.

Release moves are deterministic now — but ordering still matters to reviewers. If you maintain a large unreleased backlog, entries will be moved in a stable, predictable order after this upgrade. Diff your first post-upgrade release carefully: previously-nondeterministic ordering means a one-off reshuffle in CHANGELOG.md is expected, and you do not want that noise mixed into a feature PR.

Invalid XML surfaces as a warning, not an exception. Fixed in #18. This is friendlier, but it changes your error handling: a malformed XML changelog no longer aborts the command, so a pipeline step that relied on a thrown exception/non-zero exit to catch corruption now needs an explicit validation step (or a stricter parse in your own code) before publishing.

Check exit codes in CI deliberately. The new explicit status codes are a behavioural change for existing scripts. Any step that previously "succeeded" while doing nothing (wrong version, missing file) will now fail the build. That is desirable — just land it as a separate, announced change so an unrelated deploy isn't blamed for the red build.

Upgrading from Laravel 10/11 is a hard floor. The PHP 8.2 / Laravel 12 minimums apply to the console environment that runs the commands, so a CI image pinned to PHP 8.1 will fail to install this version even if the app itself is fine. Bump config.platform.php in composer.json too if you use it.

Pint and PHPStan are now enforced upstream, not downstream. The release adds static analysis to the package's own CI. This does not force tooling on you, but it means type annotations and signatures are now treated as public contract — stub files and IDE hints are more reliable, while any subclassing or extension of internal classes is more likely to break between minors. Prefer the facade and the config over extending internals.

StyleCI removal is cosmetic for consumers. If you forked the package and inherited its .styleci.yml, delete it in favour of Pint; nothing in your app depends on it.

Version strings are your responsibility. The package writes whatever version you hand it — it does not read composer.json, tags, or config('app.version'). Centralise that derivation in one place (a RELEASE_VERSION env var or a small helper) or your headings and tags will drift.

Watch the working-tree state. Release commands mutate tracked files. Never run them on a dirty working tree in a deploy job, and prefer running them on a dedicated release branch/commit so a failed publish doesn't leave a half-written CHANGELOG.md on main.

Debugging tip: if a command reports "no changes" unexpectedly, check file resolution first — the configured path is resolved relative to the app base path, and a trailing-slash or filename mismatch (e.g. changelog/ vs CHANGELOG.md config keys) is the usual culprit before you suspect the package.

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.
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
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route