Skip to content

release/1.11.0#79

Merged
turegjorup merged 19 commits into
mainfrom
release/1.11.0
May 18, 2026
Merged

release/1.11.0#79
turegjorup merged 19 commits into
mainfrom
release/1.11.0

Conversation

@turegjorup
Copy link
Copy Markdown
Contributor

1.11.0 — 2026-05-19

Cuts a minor release (last release was 1.10.1). The four PRs accumulated under `[Unreleased]` are dominated by new features, so this is a MINOR bump per semver.

Included PRs

  • #78 — chore: update composer dependencies, fix php-cs-fixer deprecation
  • #77 — fix: SemverFilter must respect value2 with directional operators
  • #76 — feat: add server.type filter and sort to Installation, Site, Domain
  • #75 — feat: add semver filter on every admin version column, make version columns semver sortable

Changes in this PR

  • `CHANGELOG.md` — promote `[Unreleased]` to `[1.11.0] - 2026-05-19`, add new empty `[Unreleased]` section, add footer comparison link for 1.11.0, also fix the missing `[1.10.1]` footer link that was left out of the previous release.

Test plan

  • markdownlint clean on CHANGELOG.md (verified locally; CI re-runs).
  • After merge to main, the release tag action picks up 1.11.0 and creates the GitHub Release.
  • Back-merge main → develop.

turegjorup added 19 commits May 11, 2026 14:29
Add a reusable EasyAdmin filter for dotted-version columns that
compares using semver order (=, !=, >, >=, <, <=) instead of the
default lexicographic string comparison, so e.g. "10.5.9" correctly
sorts above "9.5.1" and "v5.5.40" sorts identically to "5.5.40".

Comparison runs in SQL via a new Doctrine DQL function
SEMVER_NUMERIC(version) that strips an optional leading v/V, then
packs major/minor/patch/extra into a sortable BIGINT using
SUBSTRING_INDEX + CAST AS UNSIGNED. A REGEXP guard on the column
excludes non-semver rows (?, unknown, "main", ...) from results
when the filter is active.

Wired into the version columns on Installation (frameworkVersion,
composerVersion), PackageVersion (version, latest), ModuleVersion
(version), Site (phpVersion), GitTag (tag) and DockerImageTag (tag).
Three independent bugs were hiding behind each other and meant the filter
silently no-oped (matched everything). Browser test against
?filters[type]=drupal&filters[frameworkVersion][comparison]=<=
&filters[frameworkVersion][value]=10.6.3 returned 11.x rows.

1. SemverFilter::apply() assumed FilterDataDto::getValue() returned the
   full compound-form array and did `if (!is_array($data)) return;`. In
   EasyAdmin 5 the DTO already splits compound forms into getValue()
   (the scalar) and getComparison() (the operator), so the early return
   fired and no constraint was added. Switched to the documented API.

2. Once the WHERE clause was added, the original draft used a DQL-level
   REGEXP keyword for the non-semver guard. DQL doesn't recognise REGEXP
   and Doctrine threw a syntax error. Moved the regex into SEMVER_NUMERIC
   itself: the function now wraps its arithmetic in
   CASE WHEN col REGEXP '...' THEN ... ELSE NULL END, so non-semver
   rows collapse to NULL and are excluded by any comparison.

3. Passing the user input through SEMVER_NUMERIC a second time emitted
   the argument-placeholder five times (the function references its
   argument once for the regex and four times for the segments), so
   PDO saw five `?` but only one bound value. Computed the numeric
   in PHP (toSemverNumeric) and bind it as a single BIGINT. Multipliers
   shrunk from 10^6 to 10^4 per segment so the precomputed value fits
   in PHP_INT_MAX.

Adds a regression test against FilterDataDto's actual shape to keep
all three from coming back.
Adds two range operators so the admin can filter by a version interval
in a single filter:

* between (inclusive) → SEMVER_NUMERIC(col) >= a AND <= b
* between (exclusive) → SEMVER_NUMERIC(col) >  a AND <  b

The exclusive variant covers the common "greater than X, lower than Y"
case directly (e.g. >10 AND <11.3 in one filter).

SemverFilterType gains a `value2` text field used as the upper bound
for the range operators (ignored otherwise). SemverFilter::apply()
validates both ends through composer/semver and binds the precomputed
BIGINTs as two parameters.

Also fixes a latent bug in the COMPARISON_CHOICES validity check that
was using values as keys; it happened to work for =/!=/etc. because the
key and value were identical, but broke once between-style entries had
distinct labels.
Clicking the column header on a version column (ver., Comp., PHP,
Tag, version/latest) now sorts in semver order instead of
lexicographic, so 10.5.9 correctly comes above 9.5.1 and 11.2.10
above 11.2.8.

Implemented with a tiny SemverSort helper that walks the
QueryBuilder's existing orderBy parts and rewrites
"entity.<prop> <dir>" into
"SEMVER_NUMERIC(entity.<prop>) <dir>" for the listed properties.
Each affected CRUD controller overrides createIndexQueryBuilder()
to invoke it for its version columns:

* InstallationCrudController: frameworkVersion, composerVersion
* PackageVersionCrudController: version, latest
* ModuleVersionCrudController: version
* SiteCrudController: phpVersion
* GitTagCrudController: tag
* DockerImageTagCrudController: tag

Non-matching ORDER BY parts are left untouched, so combined
sorts (e.g. ORDER BY type ASC, frameworkVersion DESC) still work.
…ollerTrait

The six CRUD controllers all had the same createIndexQueryBuilder()
override calling SemverSort::apply() with a property list — plus
seven matching use statements each.

Extracted the boilerplate into App\Trait\SemverSortableCrudControllerTrait,
which declares one abstract semverSortedProperties(): array hook and
provides the override. Each controller now reduces to:

    use SemverSortableCrudControllerTrait;

    protected function semverSortedProperties(): array
    {
        return ['frameworkVersion', 'composerVersion'];
    }

Net −38 lines across the six controllers; behavior unchanged.
feat: add semver filter to admin version columns
Filling the upper-bound field together with >=, >, <=, or < used to
silently drop the upper bound, so ?comparison=>=&value=11.0.0&value2=11.2.0
returned everything >= 11.0.0 instead of [11.0.0, 11.2.0].

apply() now auto-promotes to a range whenever value2 is supplied with
a directional operator. The operator carries inclusivity (>=/<= →
inclusive, >/< → exclusive) and the two values are sorted numerically
so the order the user typed them in doesn't matter. = and != still
treat the second value as ignored (exact match semantics).

Form placeholder updated to "upper bound (optional, makes it a range)"
so it no longer reads as exclusive to between.
fix: SemverFilter must respect value2 with directional operators
Adds a "Server type" dropdown filter (Prod / Stg / DevOps / GPU via
ServerTypeType::CHOICES) and makes the Type column header clickable
to sort on those three admin lists.

ServerTypeFilter learned to handle dotted property names by joining
the relation itself — EasyAdmin doesn't auto-join for filters on
nested paths (EasyCorp/EasyAdminBundle#4120).
The filter reuses the plain relation name as the join alias to match
EA's own sort-side auto-join, so combining filter + sort on the same
association produces a single JOIN in the generated SQL.
Codecov flagged 0% patch coverage on the new dotted-path handling.
Three KernelTest cases cover:

* flat property → no JOIN, compares on root alias
* nested property → auto-LEFT-JOINs the relation under the plain alias
* nested property when the alias already exists → no duplicate JOIN
feat: add server.type filter and sort to Installation, Site, Domain
* composer update — minor/patch bumps across Symfony 8.0.9→8.0.11,
  EasyAdmin 5.0.7→5.0.8, php-cs-fixer 3.95.1→3.95.2, PHPUnit
  13.1.8→13.1.10, PHPStan, Doctrine and friends. No security
  advisories. composer.json validates strict.
* Replace the deprecated PHP_CS_FIXER_IGNORE_ENV=1 env var on the
  coding-standards scripts with $config->setUnsupportedPhpVersionAllowed(true)
  in .php-cs-fixer.dist.php (the supported replacement; the env var
  is removed in php-cs-fixer 4.0).
chore: update composer dependencies, fix php-cs-fixer deprecation
@turegjorup turegjorup self-assigned this May 18, 2026
@github-actions
Copy link
Copy Markdown

API Specification - Non-breaking changes

API Changelog 1.0.0 vs. 1.0.0

No changes detected

@turegjorup turegjorup merged commit 4402754 into main May 18, 2026
15 checks passed
@turegjorup turegjorup deleted the release/1.11.0 branch May 18, 2026 22:59
@codecov-commenter
Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 76.40449% with 42 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (main@8126bb9). Learn more about missing BASE report.

Files with missing lines Patch % Lines
src/Doctrine/Functions/SemverNumeric.php 0.00% 22 Missing ⚠️
src/Form/Type/Admin/SemverFilterType.php 0.00% 19 Missing ⚠️
src/Admin/SemverSort.php 93.75% 1 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##             main      #79   +/-   ##
=======================================
  Coverage        ?   41.63%           
  Complexity      ?      866           
=======================================
  Files           ?      125           
  Lines           ?     2738           
  Branches        ?        0           
=======================================
  Hits            ?     1140           
  Misses          ?     1598           
  Partials        ?        0           
Flag Coverage Δ
unittests 41.63% <76.40%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@turegjorup turegjorup restored the release/1.11.0 branch May 18, 2026 22:59
@turegjorup turegjorup deleted the release/1.11.0 branch May 18, 2026 23:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants