adachsoft/release-validator

release-validator

Maintainers

Package info

gitlab.com/a.adach/release-validator

Issues

pkg:composer/adachsoft/release-validator

Transparency log

Statistics

Installs: 21

Dependents: 1

Suggesters: 0

Stars: 0

v0.3.1 2026-07-30 13:49 UTC

This package is auto-updated.

Last update: 2026-07-30 11:50:04 UTC


README

Release-validator is a small PHP library that validates the correctness of a package release in a local Git repository. It focuses on typical mistakes made during automated releases:

  • tag does not point to the latest commit,
  • missing changelog entry for the released version,
  • invalid changelog format,
  • truncated changelog (lossy regeneration),
  • dirty working tree at release time.

The library is designed to be used by other tools (CLI, CI pipelines, agents) as a backend for pre-release checks.

Requirements

  • PHP >= 8.3
  • Git repository available on the local filesystem
  • Composer for installation

Runtime dependencies (installed automatically via Composer):

  • adachsoft/gitlib
  • adachsoft/changelog-linter
  • adachsoft/collection

Installation

Install via Composer:

composer require adachsoft/release-validator

This will also pull the required supporting libraries (gitlib, changelog-linter, collection).

Architecture overview

The library follows a few simple patterns:

  • Strategy – each validation rule is implemented as a separate class that implements ReleaseValidatorInterface. Adding a new rule means adding a new class.
  • Ports & Adapters – validators do not talk to Git or the changelog directly. They depend only on:
    • GitReleaseInfoInterface (Git port),
    • ChangelogInspectorInterface (changelog port).
  • Facade + FactoryReleaseValidationFacade is the main entry point. It is assembled by ReleaseValidationFacadeFactory, which wires all validators, adapters and services together.
  • Immutable collections & DTOs – all collections are based on adachsoft/collection, and DTOs are final readonly objects.

This separation makes the library easy to test and extend.

Quick start

The most common usage is to validate a release for the current repository and changelog file.

<?php

declare(strict_types=1);

use AdachSoft\ReleaseValidator\Collection\ValidatorCodeCollection;
use AdachSoft\ReleaseValidator\Dto\ReleaseValidationConfigDto;
use AdachSoft\ReleaseValidator\Dto\ReleaseValidationRequestDto;
use AdachSoft\ReleaseValidator\Facade\ReleaseValidationFacadeFactory;

$config = new ReleaseValidationConfigDto(
    repositoryPath: __DIR__,
    changelogPath: 'CHANGELOG.md',
);

$facade = ReleaseValidationFacadeFactory::create($config);

// Validate the latest semver tag (version is resolved automatically):
$request = new ReleaseValidationRequestDto();
$result = $facade->validateRelease($request);

if ($result->valid) {
    echo sprintf("Release %s (%s) is valid.\n", $result->version, $result->tagName);
    return;
}

echo sprintf("Release %s (%s) is INVALID.\n", $result->version, $result->tagName);

foreach ($result->violations->toArray() as $violation) {
    echo sprintf(
        "[%s] %s: %s\n",
        $violation->validatorCode,
        $violation->code,
        $violation->message,
    );
}

You can also target a specific version and/or restrict which validators should run:

// Validate version 1.2.3 using only selected validators
$request = new ReleaseValidationRequestDto(
    version: '1.2.3',
    validatorCodes: new ValidatorCodeCollection([
        'tag_points_to_head',
        'changelog_entry_exists',
    ]),
);

$result = $facade->validateRelease($request);

The ReleaseValidationResultDto::toArray() method is convenient when you want to serialize the result, e.g. to JSON:

$json = json_encode($result->toArray(), JSON_PRETTY_PRINT);

Built-in validators

The library ships with the following validators (codes are stable and intended to be used in tooling):

CodeClass nameDescription
tag_points_to_headTagPointsToHeadValidatorEnsures that the release tag exists and points to the current HEAD commit. Detects both missing tags and tags pointing to old commits.
changelog_entry_existsChangelogEntryExistsValidatorEnsures that the changelog contains an entry for the validated version. Missing changelog or unparsable file is treated as a release problem (violations).
changelog_formatChangelogFormatValidatorValidates the changelog format using adachsoft/changelog-linter and reports each format error as a separate violation.
changelog_not_truncatedChangelogNotTruncatedValidatorCompares the set of versions in the previous release changelog with the current one and reports missing versions (truncated history).
clean_working_treeCleanWorkingTreeValidatorEnsures that the working tree is clean (no staged/modified/untracked/deleted files) when validating the release.

All validators implement ReleaseValidatorInterface and return a ViolationCollection. An empty collection means the validator passed.

Violations and exceptions

The library clearly distinguishes between:

  • violations – issues with the release itself (e.g. missing tag, invalid changelog format),
  • exceptions – infrastructure problems (e.g. Git command fails, changelog file cannot be read).

Violations are represented by ViolationDto and collected in ViolationCollection:

  • validatorCode – identifier of the validator that reported the problem,
  • code – short machine-readable code (e.g. tag_not_on_head, changelog_truncated),
  • message – human-readable explanation with concrete details (tags, versions, file paths).

Infrastructure-level issues are represented by exceptions implementing ReleaseValidatorExceptionInterface, for example:

  • GitOperationFailedException,
  • ChangelogReadException,
  • UnknownValidatorCodeException,
  • InvalidConfigurationException.

Special case: when no version is explicitly requested and the repository has no semver tags, this is reported as a violation with code no_semver_tags (validatorCode: version_resolution) in the result, not as an exception — since it is an expected precondition failure of the release process, not an infrastructure problem.

Your code is expected to catch these exceptions at the boundary (e.g. in a CLI command) and decide how to report them.

Extending the validator set

You can plug in your own validators without modifying the library code. A custom validator must implement ReleaseValidatorInterface:

use AdachSoft\ReleaseValidator\Collection\ViolationCollection;
use AdachSoft\ReleaseValidator\Contract\ReleaseValidatorInterface;
use AdachSoft\ReleaseValidator\Dto\ReleaseValidationContextDto;
use AdachSoft\ReleaseValidator\Dto\ViolationDto;

final readonly class MyCustomValidator implements ReleaseValidatorInterface
{
    public const string CODE = 'my_custom_rule';

    public function getCode(): string
    {
        return self::CODE;
    }

    public function validate(ReleaseValidationContextDto $context): ViolationCollection
    {
        // Implement your logic and return a ViolationCollection
        return new ViolationCollection([]);
    }
}

To wire additional validators, use ReleaseValidationFacadeFactory::createWithValidators():

use AdachSoft\ReleaseValidator\Collection\ReleaseValidatorCollection;
use AdachSoft\ReleaseValidator\Facade\ReleaseValidationFacadeFactory;

$config = new ReleaseValidationConfigDto(__DIR__, 'CHANGELOG.md');

$extraValidators = new ReleaseValidatorCollection([
    new MyCustomValidator(),
]);

$facade = ReleaseValidationFacadeFactory::createWithValidators($config, $extraValidators);

Your validators will be executed in addition to the built-in ones. They can also depend on the same ports (GitReleaseInfoInterface, ChangelogInspectorInterface) if you build them manually and inject the adapters yourself.

Configuration notes

  • repositoryPath must point to a directory that contains a .git folder; otherwise InvalidConfigurationException is thrown by the factory.
  • changelogPath can be relative to the repository root or an absolute path.
  • When version in ReleaseValidationRequestDto is null, the facade resolves the latest semver tag automatically (e.g. v1.2.3).
  • Versions in changelog are normalized to not contain the leading v/V prefix.

License

This library is open source software released under the MIT License.