Set up Adobe Commerce with the Separate Packages GRA pattern
The directory structure
The final directory structure of a full Adobe Commerce installation with the Separate Packages GRA pattern has this directory structure:
.
├── app/
│ └── etc/
│ └── config.php
├── packages/
│ └── ...
├── composer.json
└── composer.lock
A production Git repository has this directory structucture:
.
├── app/
│ └── etc/
│ └── config.php
├── composer.json
└── composer.lock
The difference is that the production instances install from Composer, where the monorepo holds its own copy of every package inside the packages directory.
Prepare a production repository
Create a repository for the first Adobe Commerce instance, which represents a web store for Brand X.
mkdir gra-monorepo-brand-x
cd gra-monorepo-brand-x
composer create-project --repository-url=https://repo.magento.com/ magento/project-enterprise-edition .
git init
git remote add origin git@github.com:AntonEvers/gra-monorepo-brand-x.git
git add composer.json composer.lock
git commit -m 'initialize Brand X repository'
git push -u origin main
Install Adobe Commerce with bin/magento setup:install
. Commit the resulting app/etc/config.php
and the composer files. Composer manages anything else so nothing else should be in Git.
Prepare the monorepo repository
The monorepo repository starts with the same steps.
mkdir gra-monorepo
cd gra-monorepo
composer create-project --repository-url=https://repo.magento.com/ magento/project-enterprise-edition .
Install Adobe Commerce with bin/magento setup:install
, commit and push.
git init
git remote add origin git@github.com:AntonEvers/gra-monorepo.git
git add composer.json composer.lock app/etc/config.php
git commit -m 'initialize monorepo GRA development repository'
git push -u origin main
Prepare for monorepo development
For monorepo development, make the following changes to your composer.json file:
- Change the name and description of the package so that it is clear that this package is your monorepo package.
- Delete the version attribute from composer.json, because the version is managed using Git tags for this repository.
- Replace the require section with a meta package which is created later.
- Change minimum stability to dev.
- Add a path type repository that points to
packages/*/*
to host monorepo packages, including branch aliases for each package it contains - Add a branch alias for the project itself
The following Git diff shows the difference between a clean Adobe Commerce install and the changes mentioned above:
@@ -1,6 +1,6 @@
{
- "name": "magento/project-enterprise-edition",
- "description": "eCommerce Platform for Growth (Enterprise Edition)",
+ "name": "antonevers/gra-monorepo",
+ "description": "Monorepo repository for Global Reference Architecture development",
"type": "project",
"license": [
"proprietary"
@@ -15,11 +15,8 @@
"preferred-install": "dist",
"sort-packages": true
},
- "version": "2.4.7-p3",
"require": {
- "magento/product-enterprise-edition": "2.4.7-p3",
- "magento/composer-dependency-version-audit-plugin": "~0.1",
- "magento/composer-root-update-plugin": "^2.0.4"
+ "antonevers/gra-meta-brand-x": "self.version"
},
"autoload": {
"exclude-from-classmap": [
@@ -69,16 +66,33 @@
"Magento\\Tools\\Sanity\\": "dev/build/publication/sanity/Magento/Tools/Sanity/"
}
},
- "minimum-stability": "stable",
+ "minimum-stability": "dev",
"prefer-stable": true,
"repositories": [
{
+ "type": "path",
+ "url": "packages/*/*",
+ "options": {
+ "versions": {
+ "antonevers/gra-meta-brand-x": "1.4.x-dev",
+ "antonevers/gra-meta-foundation": "1.4.x-dev",
+ "antonevers/gra-component-foundation": "1.4.x-dev",
+ "antonevers/module-gra": "1.4.x-dev",
+ "antonevers/module-3rdparty": "1.4.x-dev",
+ "antonevers/module-local": "1.4.x-dev"
+ }
+ }
+ },
+ {
"type": "composer",
"url": "https://repo.magento.com/"
}
],
"extra": {
- "magento-force": "override"
+ "magento-force": "override",
+ "branch-alias": {
+ "dev-main": "1.4.x-dev"
+ }
}
}
Use metapackages
Download the example code from AntonEvers/gra-meta-foundation on GitHub to get the metapackages and the sample modules that are used in this example.
Composer metapackages bundle multiple composer packages together under a single package. When a metapackage is required, all packages it bundles are automatically installed through the Composer require section of the metapackage.
For this example, there are two metapackages:
- antonevers/gra-meta-brand-x: A metapackage that contains everything that makes up “Brand X”
- antonevers/gra-meta-foundation: A metapackage that contains everything that is always installed in any brand
The brand metapackage requires the foundation metapackage. When brand metapackage is required, the foundation metapackage is automatically required as well. Please see the two composer.json files of the metapackages to see how they relate:
antonevers/gra-meta-brand-x:
{
"name": "antonevers/gra-meta-brand-x",
"type": "metapackage",
"license": [
"OSL-3.0",
"AFL-3.0"
],
"require": {
"antonevers/gra-meta-foundation": "^1.4",
"antonevers/module-local": "^1.4"
}
}
antonevers/gra-meta-foundation:
{
"name": "antonevers/gra-meta-foundation",
"type": "metapackage",
"license": [
"OSL-3.0",
"AFL-3.0"
],
"require": {
"antonevers/gra-component-foundation": "^1.4",
"antonevers/module-gra": "^1.4",
"antonevers/module-3rdparty": "^1.4",
"magento/composer-dependency-version-audit-plugin": "~0.1",
"magento/composer-root-update-plugin": "^2.0.4",
"magento/product-enterprise-edition": "2.4.7-p3"
}
}
Metapackages are a good way to organize code that belongs together. Use metapackages to define groups of packages that are regional, global, brand-specific or any grouping that makes sense for you. If you maintain multiple installations of Adobe Commerce, matapackages a safe and versatile way of defining the context in which a package is expected.
Metapackages exist in the monorepo inside the packages
directory. There, the directory structure of the vendor
is mirrored:
.
├── packages/
│ └── antonevers
│ ├── gra-meta-brand-x
│ │ └── composer.json
│ └── gra-meta-foundation
│ └── composer.json
├── composer.json
└── composer.lock
Add and develop modules
Modules in the monorepo exist in the packages
directory. This way Composer can find them through the path type repository.
Download the example code from AntonEvers/gra-meta-foundation on GitHub to get the metapackages and the sample modules that are used in this example.
.
├── packages/
│ └── antonevers
│ ├── gra-meta-brand-x
│ ├── gra-meta-foundation
│ ├── module-3rdparty
│ ├── module-gra
│ └── module-local
├── composer.json
└── composer.lock
You can have multiple namespaces inside the packages
directory if needed.
Development takes place in the packages directory. Symlinks to the packages inside the packages
directory are created in the vendor
directory once you run composer update
. This way, the code becomes part of the Adobe Commerce installation.
Run bin/magento module:enable --all
or for only specific modules to enable the modules that were added.
By now you should have a working Adobe Commerce installation with the three sample modules installed and working. You can validate if the modules are installed and working by running the commands:
bin/magento test:gra
bin/magento test:3rdparty
bin/magento test:local
Achieve automated package creation
There are multiple options to achieve automated package creation. Some options are:
- Private Packagist
- Simplyfy Monorepo Builder
- Build your own solution
Private Packagist automates recognizing packages in the Git monorepo and exposes them through Composer. It is compatible with Adobe Commerce, fast, low-maintenance and error-prone, which is why this guide focuses on the Private Packagist option.
It is beyond the scope of this guide to explain how to set up Private Packagist, please see the docs.
There is the possibility to turn a package into a monorepo once you have set up organization syncing and your Git repositories are automatically syncing to Private Packagist.
First, go to the packages tab and find the monorepo:
Click on the monorepo package and click “Edit” in the details screen, which takes you to the following page:
Underneath the first input field, there is a link saying: Create a multi-package repository. Click this link.
Define the location where composer packages can be found inside your monorepo. In the example, the location is packages/**/composer.json
. Change the location to limit or broaden where Private Packagist searches for packages to extract.
The packages tab will show all found packages after saving, and the monorepo itself will no longer be visible as a Composer package:
A version is created in Composer for each package inside the monorepo, for every tag or branch that is created on the monorepo in Git.
Install the packages to the production environment
Follow the instructions from Private Packagist to add Private Packagist as a composer repository. Private Packagist can and should be used as a mirror for all your Composer repositories and Git repositories, including packagist.org. That way credentials do not have to be shared with developers and you have complete control over each package. This example does not follow this best practice as it would expose the Adobe Commerce codebase publicly.
Download GRA Monorepo Brand X from GitHub to see an example of a production store.
In the production store, there is no packages
directory, and all packages are installed through Composer. The only package that is required is:
"require": {
"antonevers/gra-meta-brand-x": "^1.0"
},
Yet all of Adobe Commerce and the entire GRA is installed through this metapackage’s requirements.
Versioning
All packages in the monorepo receive the same version as the monorepo itself. Think of it as publishing new versions of the entire application. On production, however, you can install a mix of packages from different monorepo versions.
Ephemeral environments
If you use ephemeral environments or you plan to use them, the monorepo is an excellent choice. Every version and branch of the monorepo contains all Adobe Commerce, third party and custom module files. With a complete installation in every branch, it is possible to run every type of test including functional tests. With other GRA setups such as the separate packages or bulk packages GRA, you would first need to build a working Adobe Commerce environment before being able to run functional tests. From a DevOps perspective, monorepo makes it much simpler.
Code examples
The code examples of this article have been combined in a set of Git repositories, which you can use to play around with the proof of concept.
- An example monorepo repository: https://github.com/AntonEvers/gra-monorepo
- An example production store: https://github.com/AntonEvers/gra-monorepo-brand-x
Commerce
- Commerce Tutorials
- Adobe Commerce Cloud
- Getting Started
- Global Reference Architecture
- Help and support
- Edge Delivery Services
- Webinars and events
- GraphQL and REST
- Adobe Developer App Builder
- Store Administration
- Customer Management
- Catalog Management
- Content Management
- Marketing Tools
- Orders and Fulfillment
- B2B for Adobe Commerce
- Tools and External services
- Commerce Intelligence
- Commerce Upgrades
- Back-end Development
- Native Front-end Luma Development
- Headless Architecture