# magento/quality-patches The Quality Patches Tool (QPT) is a command-line package (`magento/quality-patches`, v1.1.79) that delivers quality patches for Adobe Commerce and Magento Open Source. It ships a curated library of `.patch` files alongside two JSON manifests — `support-patches.json` (Adobe-authored patches) and `community-patches.json` (community-contributed patches) — and integrates with the `magento/magento-cloud-patches` infrastructure so the same tool works on both on-premises and Adobe Commerce Cloud projects. Each patch entry maps a patch ID to one or more Composer-style version constraints, ensuring the correct diff file is applied to the exact Magento release the merchant is running. The package exposes its functionality through the `./vendor/bin/magento-patches` CLI (on-premises) or `./vendor/bin/ece-patches` CLI (Cloud), backed by the `Magento\QualityPatches\Info` PHP class that resolves all file-system paths. A separate `UpdateInfoJson` script aggregates `support-patches.json`, `community-patches.json`, and the remote Cloud patches manifest into a single `patches-info.json` export used by the QPT landing page. An integrity test suite (PHPUnit) guards the patch registry: it validates JSON structure, version-constraint syntax, file existence, patch uniqueness, deprecated-patch dependencies, and category assignments. Acceptance (Codeception) tests spin up Docker-based Magento environments to confirm patches apply cleanly end-to-end. --- ## CLI — `status` command Prints a table of all patches applicable to the currently installed Magento version, showing patch ID, description, type (Optional / Required / Deprecated / Custom), status (Applied / Not applied / N/A), and affected components. ```bash # On-premises — show patch status for the current Magento installation ./vendor/bin/magento-patches status # Expected output (excerpt): # +--------------+-------------------------------------------------------------+-----------+-------------+ # | Id | Title | Type | Status | # +--------------+-------------------------------------------------------------+-----------+-------------+ # | ACSD-59280 | Fixes "Call to undefined method ReflectionUnionType..." | Optional | Not applied | # | MDVA-26694-V2| Fixes product/catalog caches expiring daily | Optional | Applied | # | LYNX-839 | Remove customer group info exposure through GraphQL | Optional | Not applied | # +--------------+-------------------------------------------------------------+-----------+-------------+ # Cloud — same output via ece-patches ./vendor/bin/ece-patches status ``` --- ## CLI — `apply` command Applies one or more patches by their ID. The patch system selects the correct `.patch` file for the running Magento version automatically. After applying, flush the cache. ```bash # On-premises — apply two patches at once ./vendor/bin/magento-patches apply ACSD-59280 LYNX-839 # Verify they are now "Applied" ./vendor/bin/magento-patches status # Flush the cache so changes take effect ./bin/magento cache:clean # Cloud — add to .magento.env.yaml, then deploy # .magento.env.yaml: stage: build: QUALITY_PATCHES: - ACSD-59280 - LYNX-839 - B2B-2674 # Apply locally before pushing ./vendor/bin/ece-patches apply # Verify ./vendor/bin/ece-patches status ``` --- ## CLI — `revert` command Reverts one or more previously applied patches, or all patches at once. On Cloud the revert order is: custom patches → quality patches → cloud-required patches. ```bash # On-premises — revert a single patch ./vendor/bin/magento-patches revert ACSD-59280 # On-premises — revert all applied patches ./vendor/bin/magento-patches revert --all # Cloud — revert all patches in a local environment ./vendor/bin/ece-patches revert # Flush cache after reverting ./bin/magento cache:clean ``` --- ## Installation QPT is a Composer package. On Cloud it ships automatically with `ece-tools`; on-premises it is added as an explicit dependency. ```bash # On-premises installation composer require magento/quality-patches # Cloud — QPT is bundled with ece-tools; update ece-tools to get the latest patches composer update magento/ece-tools # Verify the installed version composer show magento/quality-patches # magento/quality-patches 1.1.79 Provides quality patches for AdobeCommerce & Magento OpenSource ``` --- ## `support-patches.json` — Patch Registry Schema The central registry `support-patches.json` maps each patch ID to metadata and one or more version-constrained file references. This schema also applies to `community-patches.json`. ```json { "ACSD-59280": { "categories": ["Other"], "title": "Fixes the error \"Call to undefined method ReflectionUnionType::getName()\" happening when installing 2.4.4-pX versions.", "packages": { "magento/magento2-base": { ">=2.4.4 <2.4.4-p17": { "file": "os/ACSD-59280_2.4.4-p6.patch", "require": ["ACSD-55031"] } } } }, "MDVA-26694": { "categories": ["Catalog/Product"], "title": "Fixes the issue with product and catalog caches expiring daily, though being scheduled to expire differently.", "packages": { "magento/magento2-base": { ">=2.3.0 <2.3.6 || >=2.4.0 <2.4.1": { "file": "os/MDVA-26694_2.3.1.patch", "replaced-with": "MDVA-26694-V2" } } } }, "BUNDLE-3375": { "categories": ["Payments"], "title": "The fix adds all the necessary fields to fulfill the 3DS VISA mandate requirements when using Braintree as a payment gateway.", "packages": { "paypal/module-braintree-core": { "4.3.0": { "file": "os/BUNDLE-3375__braintree_3ds_collectDeviceData_ipAddress_2.4.4-p1-p2-p3-p4.patch" }, ">=4.3.0-p1 <4.3.0-p10": { "file": "os/BUNDLE-3375__braintree_3ds_collectDeviceData_ipAddress_2.4.4-p5-p6-p7-p8-p9-p10.patch" }, ">=4.4.0 <4.4.0-p2": { "file": "os/BUNDLE-3375__braintree_3ds_collectDeviceData_ipAddress_2.4.5-p1-p2-p3.patch" } } } }, "LYNX-839": { "categories": ["GraphQL"], "title": "Remove customer group/segments/promo rules information exposure through the GraphQL.", "packages": { "magento/magento2-base": { "2.4.8": { "file": "os/LYNX-839_CE_2.4.8.patch" } }, "magento/magento2-ee-base": { "2.4.8": { "file": "commerce/LYNX-839_EE_2.4.8.patch" } } } } } ``` --- ## `community-patches.json` — Community Patch Registry Community-contributed patches follow the same JSON schema as `support-patches.json` but reside under `patches/community/`. They are sourced from Magento GitHub pull requests and attributed to their authors. ```json { "magento2-33723": { "categories": ["Performance", "Shopping Cart"], "title": "Optimizes QuoteIdToMaskedQuoteId model. Author: @ihor-sviziev.", "packages": { "magento/magento2-base": { "2.3.7": { "file": "community/magento_magento2_33723.patch" } } } }, "magento2-34228": { "categories": ["Payments"], "title": "Fixes upgrade issue from 2.4.2 to 2.4.3 for PayPal data patch. Author: @konarshankar07.", "packages": { "magento/magento2-base": { "2.4.3": { "file": "community/magento_magento2_34228.patch" } } } }, "magento/magento2/34529": { "categories": ["Customer"], "title": "MC-41887: Validation Messages - CustomerData messages not showing up. Author: @Den4ik", "packages": { "magento/magento2-base": { "2.3.7": { "file": "community/magento_magento2_34529.patch" } } } } } ``` --- ## `Magento\QualityPatches\Info` — Path Resolution API The `Info` class is the PHP entry-point for integrations that need to locate patches and configuration files programmatically, such as the integrity test suite or custom tooling. ```php getPatchesDirectory(); // => /path/to/vendor/magento/quality-patches/patches // Resolve Adobe support patches manifest $supportConfig = $info->getSupportPatchesConfig(); // => /path/to/vendor/magento/quality-patches/support-patches.json // Resolve community patches manifest $communityConfig = $info->getCommunityPatchesConfig(); // => /path/to/vendor/magento/quality-patches/community-patches.json // Resolve patch categories definition $categoriesConfig = $info->getCategoriesConfig(); // => /path/to/vendor/magento/quality-patches/config/patch-categories.json // Resolve tests directory (used by integrity suite) $testsDir = $info->getTestsDirectory(); // => /path/to/vendor/magento/quality-patches/tests // Read and decode the support patches manifest $supportPatches = json_decode(file_get_contents($supportConfig), true); foreach ($supportPatches as $patchId => $patchData) { echo $patchId . ': ' . $patchData['title'] . PHP_EOL; foreach ($patchData['packages'] as $package => $constraints) { foreach ($constraints as $constraint => $info) { echo " applies to $package $constraint => " . $info['file'] . PHP_EOL; } } } // ACSD-59280: Fixes the error "Call to undefined method... // applies to magento/magento2-base >=2.4.4 <2.4.4-p17 => os/ACSD-59280_2.4.4-p6.patch // ... ``` --- ## `UpdateInfoJson` — Patch Info Export Script The `UpdateInfoJson` script aggregates all patch sources (support, cloud, community) into a single `patches-info.json` file consumed by the QPT landing page. It resolves compatible Magento releases for each patch using `magento_releases.json` and enriches entries with Experience League article links. ```bash # Generate patches-info.json (run from repository root with vendor/ present) php src/UpdateInfoJson.php # => patches-info.json updated successfully. Contains 1842 patches. # => Version of magento/quality-patches is 1.1.79 ``` ```php ['>=2.4.4 <2.4.4-p17'] ]; $compatibleReleases = []; foreach ($releases as $release => $dependencies) { foreach ($patchConstraints as $package => $versionConstraints) { if (!isset($dependencies[$package])) { continue; } foreach ($versionConstraints as $versionConstraint) { if (Semver::satisfies($dependencies[$package], $versionConstraint)) { $compatibleReleases[] = $release; } } } } // $compatibleReleases => ['2.4.4', '2.4.4-p1', '2.4.4-p2', ..., '2.4.4-p16'] print_r($compatibleReleases); ``` --- ## `config/patch-categories.json` — Patch Category Definitions Defines the allowed category labels used in the `categories` field of every patch entry. Categories are validated by `CategoriesIntegrityTest`. ```json [ { "name": "Performance", "description": "Patches related to application performance." }, { "name": "Web API", "description": "Patches related to REST/SOAP API requests." }, { "name": "GraphQL", "description": "Patches related to GraphQL." }, { "name": "B2B", "description": "Patches related to B2B functionality." }, { "name": "Content", "description": "Patches related to WYSIWYG, Page Builder, widgets, dynamic blocks, etc." }, { "name": "Cache", "description": "Patches related to FPC, Fastly/Varnish, Redis/Memcache, everything related to cache." }, { "name": "Cron", "description": "Patches related to issues with cron." }, { "name": "Inventory", "description": "Patches related to MSI or inventory in general." }, { "name": "Import/Export", "description": "Patches related to Import/Export functionality." }, { "name": "Catalog/Product", "description": "Patches related to products, categories, related product rules, everything related to catalog in general." }, { "name": "Payments", "description": "Patches related to payment methods." }, { "name": "Shipping", "description": "Patches related to shipping methods." }, { "name": "Emails", "description": "Patches related to email functionality." }, { "name": "Other", "description": "Patches that do not fit other categories." } ] ``` --- ## `magento_releases.json` — Magento Release Dependency Map Maps each official Magento release string to its component versions. Used by `UpdateInfoJson` (and `Semver::satisfies`) to determine which full releases are compatible with a patch's package version constraint. ```json { "2.4.8-p4": { "magento/magento2-base": "2.4.8-p4", "magento/magento2-ee-base": "2.4.8-p4", "magento/magento2-b2b-base": "1.5.2-p4", "magento/inventory-metapackage":"1.2.8-p4", "magento/module-page-builder": "2.2.6-p3", "magento/security-package": "1.1.7-p4", "paypal/module-braintree-core": "4.7.0" }, "2.4.8": { "magento/magento2-base": "2.4.8", "magento/magento2-ee-base": "2.4.8", "magento/magento2-b2b-base": "1.5.2", "magento/inventory-metapackage":"1.2.8", "magento/module-page-builder": "2.2.6", "magento/security-package": "1.1.7", "paypal/module-braintree-core": "4.7.0" }, "2.4.7-p9": { "magento/magento2-base": "2.4.7-p9", "magento/magento2-b2b-base": "1.5.2-p4", "paypal/module-braintree-core": "4.6.1-p5" } } ``` --- ## Integrity Test Suite (PHPUnit) The integrity test suite (`tests/integrity/`) validates every JSON manifest entry before patches are shipped. Run via `composer test:integrity`. ```bash # Run all integrity tests composer test:integrity # or directly phpunit --configuration ./tests/integrity # Run a specific test class phpunit --configuration ./tests/integrity \ --filter ConfigStructureTest # Expected output on a clean repository: # OK (5 tests, 5 assertions) ``` ```php =1.1.6 // ~2.3.6 || >=2.4.0 // >2.4.0 <2.4.1 || >=2.4.3 <=2.4.3-p2 // PatchFilesIntegrityTest detects orphaned .patch files and cross-ID duplicates: use Magento\QualityPatches\Test\Integrity\Testsuite\PatchFilesIntegrityTest; // testForOrphanedPatches — fails if a .patch file exists on disk but has no registry entry // testPatchUniquenessAcrossPackages — fails if the same file is registered under two different base IDs // DeprecatedDependencyTest prevents shipping a non-deprecated patch that depends on a deprecated one: use Magento\QualityPatches\Test\Integrity\Testsuite\DeprecatedDependencyTest; // testAbsenceOfDependenciesOnDeprecatedPatches // testReplacedWithPatchConstraint — replacement patch must overlap the replaced patch's version range ``` --- ## Code Quality Scripts The repository enforces PSR-4 autoloading correctness, PHP CodeSniffer, and PHPMD as part of its CI pipeline. ```bash # Run all quality checks at once composer test:all # Validate PSR-4 autoload map (strict mode) composer test:psr4 # Equivalent: composer dump-autoload -o --strict-psr # PHP CodeSniffer against src/ composer test:phpcs # Equivalent: phpcs src --standard=tests/static/phpcs-ruleset.xml -p -n # PHP Mess Detector against src/ composer test:phpmd # Equivalent: phpmd src xml tests/static/phpmd-ruleset.xml ``` --- ## Acceptance Tests (Codeception / Cloud) Functional acceptance tests spin up full Magento Cloud environments via Docker and verify patches apply without breaking the storefront. Each `*Cest` class targets a specific Magento + B2B version matrix. ```php '2.4.8', 'magentoVersion' => '2.4.8', 'b2bVersion' => '1.5.2'], ['templateVersion' => '2.4.8', 'magentoVersion' => '2.4.8-p1', 'b2bVersion' => '1.5.2-p1'], ['templateVersion' => '2.4.8', 'magentoVersion' => '2.4.8-p2', 'b2bVersion' => '1.5.2-p2'], ['templateVersion' => '2.4.8', 'magentoVersion' => '2.4.8-p3', 'b2bVersion' => '1.5.2-p3'], ['templateVersion' => '2.4.8', 'magentoVersion' => '2.4.8-p4', 'b2bVersion' => '1.5.2-p4'], ]; } } // The AbstractCest::testPatches method: // 1. Clones a Magento Cloud template at the given version // 2. Injects magento/quality-patches v1.1.999 (local artifact) // 3. Copies .apply_quality_patches.env.yaml as .magento.env.yaml // 4. Runs cloud-build + cloud-deploy in Docker // 5. Asserts the storefront loads: $I->see('Home page') // Run acceptance tests (requires Docker and Cloud credentials) ./vendor/bin/codecept run --steps Acceptance ``` --- QPT's primary use cases are hotfix delivery and regression mitigation for production Adobe Commerce and Magento Open Source deployments without requiring a full version upgrade. On-premises merchants use the `magento-patches` CLI to selectively apply and revert individual patches, while Cloud merchants declare the desired patch IDs in `.magento.env.yaml` so patches are applied automatically during the build/deploy pipeline. The patch registry covers all Magento releases from 2.3.0 through 2.4.8-p4, spans categories including Performance, GraphQL, B2B, Payments, Cache, Inventory, and Shipping, and supports advanced lifecycle features: patch deprecation (`deprecated: true`), versioned replacements (`replaced-with`), inter-patch dependencies (`require`), and multi-package patches (a single patch ID covering both `magento2-base` and `magento2-ee-base`). Integration with custom tooling is straightforward: the `Magento\QualityPatches\Info` class exposes all file-system paths, `magento_releases.json` provides the release-to-component version mapping needed for `Semver::satisfies` calls, and the full patch registry is available as structured JSON. Teams maintaining forks or private patch sets can follow the same JSON schema for `support-patches.json` and point the `Info::getSupportPatchesConfig()` override at a custom manifest, or place custom `.patch` files in the `/m2-hotfixes` directory on Cloud projects to have them applied after QPT patches without any registry changes.