myopensoft/php-version-bumper

Bump your project's semantic version from Conventional Commits and generate a Keep-a-Changelog entry. Framework-free, zero dependencies.

Maintainers

Package info

gitlab.com/myopensoft/php-version-bumper

Issues

pkg:composer/myopensoft/php-version-bumper

Transparency log

Statistics

Installs: 6

Dependents: 1

Suggesters: 0

Stars: 0

1.0.0 2026-08-03 09:56 UTC

This package is auto-updated.

Last update: 2026-08-03 05:23:46 UTC


README

Bump your project's semantic version from Conventional Commits and generate a Keep a Changelog entry, using the commits since your last git tag. Framework-free, zero runtime dependencies — a single git binary on PATH is all it needs.

Installation

composer require --dev myopensoft/php-version-bumper

CLI usage

vendor/bin/version-bump [options]
OptionEffect
--dry-runPreview the next version and changelog without writing
--commitStage and commit the version + changelog changes
--tagCreate a git tag for the new version
--pushPush the branch and tag to the configured remote
--help, -hShow usage
--version, -VShow the version-bump version

The bump level follows Conventional Commits: feat → minor, fix/perf → patch, and any commit marked breaking (feat!: or a BREAKING CHANGE: footer) → major. The baseline is your most recent git tag; if no commit since that tag warrants a release, the command prints a notice and exits 0.

Committing, tagging, and pushing are each opt-in — a bare vendor/bin/version-bump only writes the version file and the changelog.

Worked example

Given a repo tagged 1.0.0 with these commits since the tag:

feat(api): add export endpoint
fix(cli): correct exit code on failure
$ vendor/bin/version-bump --dry-run
Bumping 1.0.0 → 1.1.0 (Minor).
## [1.1.0] — 2026-08-02

### Added
- api: add export endpoint

### Fixed
- cli: correct exit code on failure

Dry run — nothing written, committed, or pushed.

Dropping --dry-run writes VERSION and prepends the entry to CHANGELOG.md. Adding --commit --tag then creates the release commit and tag:

$ vendor/bin/version-bump --commit --tag
Bumping 1.0.0 → 1.1.0 (Minor).
## [1.1.0] — 2026-08-02
...
Released 1.1.0.

$ git log --oneline -1 && git tag --list '1.1.0'
4c7bc98 chore(release): 1.1.0
1.1.0

Configuration: version-bumper.php

Drop a version-bumper.php in your project root and the CLI will pick it up automatically; it is entirely optional — with no file present, the defaults below already give you a working setup (a VERSION file plus a CHANGELOG.md, both in the current working directory).

<?php

return [
    // Where the current version lives: 'file', 'config_file', or 'git_tag'.
    'source' => 'file',

    // Path to the plain-text version file, used when source is 'file'.
    'version_file' => 'VERSION',

    'config_file' => [
        // Path to the file to regex-patch, used when source is 'config_file'.
        'path' => '',

        // A regex with exactly one capture group around the version literal.
        'pattern' => '',
    ],

    // Path to the Keep-a-Changelog file that new entries are prepended to.
    'changelog' => 'CHANGELOG.md',

    // Format passed to DateTimeImmutable::format() for the changelog entry date.
    'date_format' => 'Y-m-d',

    // Commit type => changelog section heading. Types left out of this map
    // are parsed but never appear in the changelog (e.g. docs, chore, test).
    'sections' => [
        'feat' => 'Added',
        'fix' => 'Fixed',
        'perf' => 'Changed',
    ],

    // Commit type => bump level ('major', 'minor', or 'patch'). Types left
    // out of this map never trigger a release on their own. A commit marked
    // breaking (`feat!:` or a `BREAKING CHANGE:` footer) always bumps major,
    // regardless of this map.
    'bumps' => [
        'feat' => 'minor',
        'fix' => 'patch',
        'perf' => 'patch',
    ],

    'git' => [
        // Remote pushed to when --push is passed.
        'remote' => 'origin',

        // Branch pushed to when --push is passed. null (the default)
        // resolves to the current branch at run time.
        'branch' => null,
    ],
];

Paths are resolved relative to the current working directory unless they are absolute.

Version sources

  • file (default) — reads and writes a plain-text version string in version_file. A missing or empty file reads as 0.0.0.
  • config_file — regex-patches a version literal inside an arbitrary file, e.g. a 'version' entry in some other config file. Both config_file.path and config_file.pattern are required: selecting this source while either is left at its empty-string default throws an InvalidArgumentException before anything is read or written.
  • git_tag — reads the current version from the latest git tag; write() is a no-op, since the tag created by --tag is itself the new source of truth.

Library usage

Everything the CLI does is reachable directly, if you'd rather drive a release from your own script:

use Myopensoft\VersionBumper\Config;
use Myopensoft\VersionBumper\ReleaseFactory;
use Myopensoft\VersionBumper\ReleaseOptions;

$release = (new ReleaseFactory(Config::fromArray([]), (string) getcwd()))
    ->releaseRunner()
    ->run(new ReleaseOptions(dryRun: true));

echo $release->to;             // '1.1.0'
echo $release->changelogEntry; // '## [1.1.0] — 2026-08-02 …'

Config::fromArray([]) applies the same built-in defaults as an absent version-bumper.php. Release also carries from, bump, status, and the buffered messages the CLI prints.

Laravel

myopensoft/laravel-version-bumper wraps this package as an Artisan command (php artisan version:bump) with a published config file. If you're on Laravel, install that package instead of wiring this one up by hand.

Testing & static analysis

composer test       # Pest
composer analyse    # PHPStan level 10
composer psalm      # Psalm errorLevel 1
composer format     # Pint

License

The MIT License (MIT). Please see the License File for more information.