From f00b9267b40104b4d800019934946c9cd87e8489 Mon Sep 17 00:00:00 2001 From: Thomas Hauschild <7961978+Morgy93@users.noreply.github.com> Date: Mon, 1 Jun 2026 18:36:27 +0200 Subject: [PATCH] feat: add dev env --- .../ddev-opensearch/manifest.yaml | 9 + .ddev/commands/web/install-magento | 82 +++++ .ddev/commands/web/magento | 17 + .ddev/commands/web/mago | 19 ++ .ddev/commands/web/phpcbf | 42 +++ .ddev/commands/web/phpcs | 45 +++ .ddev/commands/web/phpstan | 42 +++ .ddev/config.yaml | 295 ++++++++++++++++++ .ddev/docker-compose.opensearch.yaml | 54 ++++ .ddev/opensearch/Dockerfile | 6 + .gitattributes | 14 + .github/copilot-instructions.md | 232 ++++++++------ .gitignore | 12 + .trunk/.gitignore | 9 + .trunk/configs/.checkov.yaml | 2 + .trunk/configs/.hadolint.yaml | 5 + .trunk/configs/.markdownlint.yaml | 2 + .trunk/configs/.shellcheckrc | 7 + .trunk/configs/.yamllint.yaml | 7 + .trunk/trunk.yaml | 42 +++ .trunkignore | 2 + CONTRIBUTING.md | 2 + README.md | 7 +- docs/development.md | 236 ++++++++++++++ 24 files changed, 1089 insertions(+), 101 deletions(-) create mode 100644 .ddev/addon-metadata/ddev-opensearch/manifest.yaml create mode 100755 .ddev/commands/web/install-magento create mode 100755 .ddev/commands/web/magento create mode 100755 .ddev/commands/web/mago create mode 100755 .ddev/commands/web/phpcbf create mode 100755 .ddev/commands/web/phpcs create mode 100755 .ddev/commands/web/phpstan create mode 100644 .ddev/config.yaml create mode 100644 .ddev/docker-compose.opensearch.yaml create mode 100644 .ddev/opensearch/Dockerfile create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 .trunk/.gitignore create mode 100644 .trunk/configs/.checkov.yaml create mode 100644 .trunk/configs/.hadolint.yaml create mode 100644 .trunk/configs/.markdownlint.yaml create mode 100644 .trunk/configs/.shellcheckrc create mode 100644 .trunk/configs/.yamllint.yaml create mode 100644 .trunk/trunk.yaml create mode 100644 .trunkignore create mode 100644 docs/development.md diff --git a/.ddev/addon-metadata/ddev-opensearch/manifest.yaml b/.ddev/addon-metadata/ddev-opensearch/manifest.yaml new file mode 100644 index 00000000..aa52ed89 --- /dev/null +++ b/.ddev/addon-metadata/ddev-opensearch/manifest.yaml @@ -0,0 +1,9 @@ +name: ddev-opensearch +repository: ddev/ddev-opensearch +version: 2.0.1 +install_date: "2024-08-29T14:19:10+02:00" +project_files: + - opensearch + - docker-compose.opensearch.yaml +global_files: [] +removal_actions: [] diff --git a/.ddev/commands/web/install-magento b/.ddev/commands/web/install-magento new file mode 100755 index 00000000..77990fbd --- /dev/null +++ b/.ddev/commands/web/install-magento @@ -0,0 +1,82 @@ +#!/usr/bin/env bash + +set -euo pipefail + +## Description: Install magento and mageforge module +## Usage: install-magento +## Example: ddev install-magento + +# Ensure we are always in the DDEV project root inside the container +cd /var/www/html || exit 1 + +# global config +MAGENTO_FOLDER="magento" + +# check if Magento is already installed +if [[ -f "${MAGENTO_FOLDER}/bin/magento" ]]; then + echo "Magento is already installed. Skipping install-magento." + exit 0 +fi + +# download magento +composer create-project \ + --repository-url=https://mirror.mage-os.org/ \ + magento/project-community-edition \ + magento-temp + +# Create Magento Folder if not exist +if [[ ! -d "${MAGENTO_FOLDER}" ]]; then + mkdir -p "${MAGENTO_FOLDER}" +fi + +# copy everything from magento-temp into magento folder +cp -a magento-temp/. "${MAGENTO_FOLDER}/" + +# remove magento-temp +rm -rf magento-temp + +# change to magento directory +cd "${MAGENTO_FOLDER}" || exit 1 + +# Remove *.sample extension +find . -name "*.sample" -type f -exec sh -c 'mv "$1" "${1%.sample}"' _ {} \; +rm -f package-lock.json # remove basic package-lock.json to avoid conflicts + +# create missing local-themes.js file for grunt tasks +echo 'module.exports = {};' >dev/tools/grunt/configs/local-themes.js + +# install magento +bin/magento setup:install \ + --admin-email=admin@mageforge.ddev.site \ + --admin-firstname=Mage \ + --admin-lastname=Forge \ + --admin-password=admin123 \ + --admin-user=admin \ + --backend-frontname=admin \ + --db-host=db \ + --db-name=db \ + --db-password=db \ + --db-user=db \ + --search-engine=opensearch \ + --opensearch-host=opensearch \ + --opensearch-port=9200 \ + --base-url=https://mageforge.ddev.site/ \ + --language=en_US + +# set developer mode +bin/magento deploy:mode:set developer + +# disable 2FA +bin/magento module:disable Magento_TwoFactorAuth Magento_AdminAdobeImsTwoFactorAuth + +# install sample data +bin/magento sampledata:deploy + +# add path repository pointing to the module at the repo root +composer config --json repositories.mageforge '{"type":"path","url":"..","options":{"symlink":true}}' + +# require module from path repo +composer require 'openforgeproject/mageforge:*' + +# enable module +bin/magento setup:upgrade diff --git a/.ddev/commands/web/magento b/.ddev/commands/web/magento new file mode 100755 index 00000000..47f3e018 --- /dev/null +++ b/.ddev/commands/web/magento @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +## Description: Run magento CLI inside the web container +## Usage: magento [flags] [args] +## Example: "ddev magento list" or "ddev magento maintenance:enable" or "ddev magento sampledata:reset" +## ProjectTypes: magento2 +## ExecRaw: true + +cd magento || exit 1 + +if [[ ! -x bin/magento ]]; then + echo 'bin/magento is not available in your installation.' + echo 'Please verify that you installed the shop in your working dir.' + exit 1 +fi + +bin/magento "$@" diff --git a/.ddev/commands/web/mago b/.ddev/commands/web/mago new file mode 100755 index 00000000..96a5acbe --- /dev/null +++ b/.ddev/commands/web/mago @@ -0,0 +1,19 @@ +#!/usr/bin/env bash + +## Description: Run Mago (PHP analysis, formatting, and linting) +## Usage: mago [options] +## Example: "ddev mago" + +set -e + +# Require Mago to be installed (avoid executing remote install scripts automatically) +if ! command -v mago >/dev/null 2>&1; then + echo "mago is not installed. Please install it first: https://carthage.software/mago" + exit 1 +fi + +# Change to module root where mago.toml is found +cd /var/www/html + +# Run Mago with provided arguments +mago "$@" diff --git a/.ddev/commands/web/phpcbf b/.ddev/commands/web/phpcbf new file mode 100755 index 00000000..9a6899be --- /dev/null +++ b/.ddev/commands/web/phpcbf @@ -0,0 +1,42 @@ +#!/usr/bin/env bash + +## Description: Run phpcbf (auto-fix coding standard issues) +## Usage: phpcbf [path] +## Example: ddev phpcbf +## Example: ddev phpcbf src/Service/StaticContentCleaner.php +## Example: ddev phpcbf vendor/openforgeproject/mageforge/src/Block + +cd /var/www/html/magento || exit 1 + +PHPCBF_BIN="vendor-bin/coding-standard/vendor/bin/phpcbf" +PHPCBF_FALLBACK="vendor-bin/coding-standard/vendor/squizlabs/php_codesniffer/bin/phpcbf" + +if [[ ! -x "${PHPCBF_BIN}" ]]; then + PHPCBF_BIN="${PHPCBF_FALLBACK}" +fi + +if [[ ! -x "${PHPCBF_BIN}" ]]; then + echo "phpcbf not found. Installing coding-standard toolchain..." + composer bin coding-standard install || exit 1 + PHPCBF_BIN="${PHPCBF_FALLBACK}" +fi + +if [[ ! -x "${PHPCBF_BIN}" ]]; then + echo "phpcbf binary still missing. Expected ${PHPCBF_FALLBACK}." + exit 1 +fi + +# Set target path - default to vendor/openforgeproject/mageforge/src if not provided +TARGET_PATH="vendor/openforgeproject/mageforge/src" +if [[ $# -gt 0 ]] && [[ ! "$1" =~ ^- ]]; then + TARGET_PATH="$1" + shift # Remove the first argument + + # If path doesn't exist from magento dir, try from workspace root + if [[ ! -e "${TARGET_PATH}" ]] && [[ -e "../${TARGET_PATH}" ]]; then + TARGET_PATH="../${TARGET_PATH}" + fi +fi + +# Run PHPCBF with optional additional flags +"${PHPCBF_BIN}" -p -s --standard=Magento2 "$@" "${TARGET_PATH}" diff --git a/.ddev/commands/web/phpcs b/.ddev/commands/web/phpcs new file mode 100755 index 00000000..f2b80066 --- /dev/null +++ b/.ddev/commands/web/phpcs @@ -0,0 +1,45 @@ +#!/usr/bin/env bash + +## Description: Run phpcs +## Usage: phpcs [path] +## Example: ddev phpcs +## Example: ddev phpcs src/Service/StaticContentCleaner.php +## Example: ddev phpcs vendor/openforgeproject/mageforge/src/Block + +cd /var/www/html/magento || exit 1 + +PHPCS_BIN="vendor-bin/coding-standard/vendor/bin/phpcs" +PHPCS_FALLBACK="vendor-bin/coding-standard/vendor/squizlabs/php_codesniffer/bin/phpcs" + +if [[ ! -x "${PHPCS_BIN}" ]]; then + PHPCS_BIN="${PHPCS_FALLBACK}" +fi + +if [[ ! -x "${PHPCS_BIN}" ]]; then + echo "phpcs not found. Installing coding-standard toolchain..." + composer bin coding-standard install || exit 1 + PHPCS_BIN="${PHPCS_FALLBACK}" +fi + +if [[ ! -x "${PHPCS_BIN}" ]]; then + echo "phpcs binary still missing. Expected ${PHPCS_FALLBACK}." + exit 1 +fi + +# Set target path - default to vendor/openforgeproject/mageforge/src if not provided +TARGET_PATH="vendor/openforgeproject/mageforge/src" +if [[ $# -gt 0 ]] && [[ ! "$1" =~ ^- ]]; then + TARGET_PATH="$1" + shift # Remove the first argument + + # If path starts with 'src/', convert to vendor path + if [[ "${TARGET_PATH}" =~ ^src/ ]]; then + TARGET_PATH="vendor/openforgeproject/mageforge/${TARGET_PATH}" + # If path doesn't exist from magento dir, try from workspace root + elif [[ ! -e "${TARGET_PATH}" ]] && [[ -e "../${TARGET_PATH}" ]]; then + TARGET_PATH="../${TARGET_PATH}" + fi +fi + +# Run PHPCS with optional additional flags +"${PHPCS_BIN}" -p -s --standard=Magento2 "$@" "${TARGET_PATH}" diff --git a/.ddev/commands/web/phpstan b/.ddev/commands/web/phpstan new file mode 100755 index 00000000..f542c26a --- /dev/null +++ b/.ddev/commands/web/phpstan @@ -0,0 +1,42 @@ +#!/usr/bin/env bash + +## Description: Run PHPStan analysis with Magento extension (same as CI pipeline) +## Usage: phpstan [path] +## Example: ddev phpstan +## Example: ddev phpstan src/Block/Inspector.php +## Example: ddev phpstan vendor/openforgeproject/mageforge/src/Service + +# Navigate to Magento root +cd /var/www/html/magento || exit 1 + +# Check if PHPStan is installed +if [[ ! -f vendor/bin/phpstan ]]; then + echo "PHPStan not found. Installing PHPStan with Magento extension..." + + # Allow PHPStan extension installer + composer config --no-plugins allow-plugins.phpstan/extension-installer true + + # Install PHPStan and Magento extension + composer require --dev --no-update bitexpert/phpstan-magento phpstan/phpstan:^2.0 phpstan/extension-installer + + # Update dependencies (limit scope to PHPStan packages) + composer update bitexpert/phpstan-magento phpstan/phpstan phpstan/extension-installer --with-dependencies + + echo "PHPStan installation complete." +fi + +# Set target path - default to vendor/openforgeproject/mageforge/src if not provided or if it's a flag +TARGET_PATH="vendor/openforgeproject/mageforge/src" +if [[ $# -gt 0 ]] && [[ ! "$1" =~ ^- ]]; then + TARGET_PATH="$1" + shift # Remove the first argument + + # If path doesn't exist from magento dir, try from workspace root + if [[ ! -e "${TARGET_PATH}" ]] && [[ -e "../${TARGET_PATH}" ]]; then + TARGET_PATH="../${TARGET_PATH}" + fi +fi + +# Run PHPStan with the same configuration as CI pipeline +echo "Running PHPStan analysis..." +vendor/bin/phpstan analyse -c vendor/openforgeproject/mageforge/phpstan.neon "$@" "${TARGET_PATH}" diff --git a/.ddev/config.yaml b/.ddev/config.yaml new file mode 100644 index 00000000..ec412de1 --- /dev/null +++ b/.ddev/config.yaml @@ -0,0 +1,295 @@ +name: mageforge +type: magento2 +docroot: magento/pub +php_version: "8.4" +webserver_type: nginx-fpm +xdebug_enabled: false +additional_hostnames: [] +additional_fqdns: [] +database: + type: mariadb + version: "10.6" +hooks: + post-start: + - exec-host: ddev npx skills experimental_install +use_dns_when_possible: true +composer_root: magento +composer_version: "2" +web_environment: [] +corepack_enable: false + +# Key features of DDEV's config.yaml: + +# name: # Name of the project, automatically provides +# http://projectname.ddev.site and https://projectname.ddev.site +# If the name is omitted, the project will take the name of the enclosing directory, +# which is useful if you want to have a copy of the project side by side with this one. + +# type: # asterios, backdrop, cakephp, codeigniter, craftcms, drupal, drupal6, drupal7, drupal8, drupal9, drupal10, drupal11, drupal12, generic, joomla, laravel, magento, magento2, php, shopware6, silverstripe, symfony, typo3, wordpress, wp-bedrock +# See https://docs.ddev.com/en/stable/users/quickstart/ for more +# information on the different project types + +# docroot: # Relative path to the directory containing index.php. + +# php_version: "8.4" # PHP version to use, "5.6" through "8.5" + +# You can explicitly specify the webimage but this +# is not recommended, as the images are often closely tied to DDEV's' behavior, +# so this can break upgrades. + +# webimage: +# It’s unusual to change this option, and we don’t recommend it without Docker experience and a good reason. +# Typically, this means additions to the existing web image using a .ddev/web-build/Dockerfile.* + +# database: +# type: # mysql, mariadb, postgres +# version: # database version, like "10.11" or "8.0" +# MariaDB versions can be 5.5-10.8, 10.11, 11.4, 11.8 +# MySQL versions can be 5.5-8.0, 8.4 +# PostgreSQL versions can be 9-18 + +# router_http_port: # Port to be used for http (defaults to global configuration, usually 80) +# router_https_port: # Port for https (defaults to global configuration, usually 443) + +# xdebug_enabled: false # Set to true to enable Xdebug and "ddev start" or "ddev restart" +# Note that for most people the commands +# "ddev xdebug" to enable Xdebug and "ddev xdebug off" to disable it work better, +# as leaving Xdebug enabled all the time is a big performance hit. + +# xhgui_http_port: "8143" +# xhgui_https_port: "8142" +# The XHGui ports can be changed from the default 8143 and 8142 +# Very rarely used + +# host_xhgui_port: "8142" +# Can be used to change the host binding port of the XHGui +# application. Rarely used; only when port conflict and +# bind_all_ports is used (normally with router disabled) + +# xhprof_mode: [prepend|xhgui|global] +# Default is "xhgui" + +# webserver_type: nginx-fpm, apache-fpm, generic + +# timezone: Europe/Berlin +# If timezone is unset, DDEV will attempt to derive it from the host system timezone +# using the $TZ environment variable or the /etc/localtime symlink. +# This is the timezone used in the containers and by PHP; +# it can be set to any valid timezone, +# see https://en.wikipedia.org/wiki/List_of_tz_database_time_zones +# For example Europe/Dublin or MST7MDT + +# composer_root: +# Relative path to the Composer root directory from the project root. This is +# the directory which contains the composer.json and where all Composer related +# commands are executed. + +# composer_version: "2" +# You can set it to "" or "2" (default) for Composer v2 +# to use the latest major version available at the time your container is built. +# It is also possible to use each other Composer version channel. This includes: +# - 2.2 (latest Composer LTS version) +# - stable +# - preview +# - snapshot +# Alternatively, an explicit Composer version may be specified, for example "2.2.18". +# To reinstall Composer after the image was built, run "ddev utility rebuild". + +# nodejs_version: "24" +# change from the default system Node.js version to any other version. +# See https://docs.ddev.com/en/stable/users/configuration/config/#nodejs_version for more information +# and https://www.npmjs.com/package/n#specifying-nodejs-versions for the full documentation. + +# corepack_enable: false +# Change to 'true' to 'corepack enable' and gain access to latest versions of yarn/pnpm + +# additional_hostnames: +# - somename +# - someothername +# would provide http and https URLs for "somename.ddev.site" +# and "someothername.ddev.site". + +# additional_fqdns: +# - example.com +# - sub1.example.com +# would provide http and https URLs for "example.com" and "sub1.example.com" +# Please take care with this because it can cause great confusion. + +# upload_dirs: "custom/upload/dir" +# +# upload_dirs: +# - custom/upload/dir +# - ../private +# +# would set the destination paths for ddev import-files to /custom/upload/dir +# When Mutagen is enabled this path is bind-mounted so that all the files +# in the upload_dirs don't have to be synced into Mutagen. + +# disable_upload_dirs_warning: false +# If true, turns off the normal warning that says +# "You have Mutagen enabled and your 'php' project type doesn't have upload_dirs set" + +# ddev_version_constraint: "" +# Example: +# ddev_version_constraint: ">= 1.24.8" +# This will enforce that the running ddev version is within this constraint. +# See https://github.com/Masterminds/semver#checking-version-constraints for +# supported constraint formats + +# working_dir: +# web: /var/www/html +# db: /home +# would set the default working directory for the web and db services. +# These values specify the destination directory for ddev ssh and the +# directory in which commands passed into ddev exec are run. + +# omit_containers: [db, ddev-ssh-agent] +# Currently only these containers are supported. Some containers can also be +# omitted globally in the ~/.ddev/global_config.yaml. Note that if you omit +# the "db" container, several standard features of DDEV that access the +# database container will be unusable. In the global configuration it is also +# possible to omit ddev-router, but not here. + +# performance_mode: "global" +# DDEV offers performance optimization strategies to improve the filesystem +# performance depending on your host system. Should be configured globally. +# +# If set, will override the global config. Possible values are: +# - "global": uses the value from the global config. +# - "none": disables performance optimization for this project. +# - "mutagen": enables Mutagen for this project. +# +# See https://docs.ddev.com/en/stable/users/install/performance/#mutagen + +# fail_on_hook_fail: False +# Decide whether 'ddev start' should be interrupted by a failing hook + +# host_https_port: "59002" +# The host port binding for https can be explicitly specified. It is +# dynamic unless otherwise specified. +# This is not used by most people, most people use the *router* instead +# of the localhost port. + +# host_webserver_port: "59001" +# The host port binding for the ddev-webserver can be explicitly specified. It is +# dynamic unless otherwise specified. +# This is not used by most people, most people use the *router* instead +# of the localhost port. + +# host_db_port: "59002" +# The host port binding for the ddev-dbserver can be explicitly specified. It is dynamic +# unless explicitly specified. + +# mailpit_http_port: "8025" +# mailpit_https_port: "8026" +# The Mailpit ports can be changed from the default 8025 and 8026 + +# host_mailpit_port: "8025" +# The mailpit port is not normally bound on the host at all, instead being routed +# through ddev-router, but it can be bound directly to localhost if specified here. + +# webimage_extra_packages: ['php${DDEV_PHP_VERSION}-tidy', 'php${DDEV_PHP_VERSION}-yac'] +# Extra Debian packages that are needed in the webimage can be added here + +# dbimage_extra_packages: [netcat, telnet, sudo] +# Extra Debian packages that are needed in the dbimage can be added here + +# use_dns_when_possible: true +# If the host has internet access and the domain configured can +# successfully be looked up, DNS will be used for hostname resolution +# instead of editing /etc/hosts +# Defaults to true + +# project_tld: ddev.site +# The top-level domain used for project URLs +# The default "ddev.site" allows DNS lookup via a wildcard + +# share_default_provider: ngrok +# The default share provider to use for "ddev share" +# Defaults to global configuration, usually "ngrok" +# Can be "ngrok" or "cloudflared" or the name of a custom provider from .ddev/share-providers/ + +# share_provider_args: --basic-auth username:pass1234 +# Provide extra flags to the share provider script +# See https://docs.ddev.com/en/stable/users/configuration/config/#share_provider_args + +# disable_settings_management: false +# If true, DDEV will not create CMS-specific settings files like +# Drupal's settings.php/settings.ddev.php or TYPO3's additional.php +# In this case the user must provide all such settings. + +# You can inject environment variables into the web container with: +# web_environment: +# - SOMEENV=somevalue +# - SOMEOTHERENV=someothervalue + +# no_project_mount: false +# (Experimental) If true, DDEV will not mount the project into the web container; +# the user is responsible for mounting it manually or via a script. +# This is to enable experimentation with alternate file mounting strategies. +# For advanced users only! + +# bind_all_interfaces: false +# If true, host ports will be bound on all network interfaces, +# not the localhost interface only. This means that ports +# will be available on the local network if the host firewall +# allows it. + +# default_container_timeout: 120 +# The default time that DDEV waits for all containers to become ready can be increased from +# the default 120. This helps in importing huge databases, for example. + +#web_extra_exposed_ports: +#- name: nodejs +# container_port: 3000 +# http_port: 2999 +# https_port: 3000 +#- name: something +# container_port: 4000 +# https_port: 4000 +# http_port: 3999 +# Allows a set of extra ports to be exposed via ddev-router +# Fill in all three fields even if you don’t intend to use the https_port! +# If you don’t add https_port, then it defaults to 0 and ddev-router will fail to start. +# +# The port behavior on the ddev-webserver must be arranged separately, for example +# using web_extra_daemons. +# For example, with a web app on port 3000 inside the container, this config would +# expose that web app on https://.ddev.site:9999 and http://.ddev.site:9998 +# web_extra_exposed_ports: +# - name: myapp +# container_port: 3000 +# http_port: 9998 +# https_port: 9999 + +#web_extra_daemons: +#- name: "http-1" +# command: "/var/www/html/node_modules/.bin/http-server -p 3000" +# directory: /var/www/html +#- name: "http-2" +# command: "/var/www/html/node_modules/.bin/http-server /var/www/html/sub -p 3000" +# directory: /var/www/html + +# override_config: false +# By default, config.*.yaml files are *merged* into the configuration +# But this means that some things can't be overridden +# For example, if you have 'use_dns_when_possible: true'' you can't override it with a merge +# and you can't erase existing hooks or all environment variables. +# However, with "override_config: true" in a particular config.*.yaml file, +# 'use_dns_when_possible: false' can override the existing values, and +# hooks: +# post-start: [] +# or +# web_environment: [] +# or +# additional_hostnames: [] +# can have their intended affect. 'override_config' affects only behavior of the +# config.*.yaml file it exists in. + +# Many DDEV commands can be extended to run tasks before or after the +# DDEV command is executed, for example "post-start", "post-import-db", +# "pre-composer", "post-composer" +# See https://docs.ddev.com/en/stable/users/extend/custom-commands/ for more +# information on the commands that can be extended and the tasks you can define +# for them. Example: +#hooks: diff --git a/.ddev/docker-compose.opensearch.yaml b/.ddev/docker-compose.opensearch.yaml new file mode 100644 index 00000000..9a6994b0 --- /dev/null +++ b/.ddev/docker-compose.opensearch.yaml @@ -0,0 +1,54 @@ +#ddev-generated +services: + opensearch: + container_name: ddev-${DDEV_SITENAME}-opensearch + build: ./opensearch + expose: + - 9200 + environment: + # see https://opensearch.org/docs/latest/install-and-configure/install-opensearch/docker/ for available options + # disables installation of demo data + - "DISABLE_INSTALL_DEMO_CONFIG=true" + # disables security plugin + - "DISABLE_SECURITY_PLUGIN=true" + - cluster.name=opensearch-cluster + - node.name=opensearch-node + - discovery.type=single-node + - bootstrap.memory_lock=true + - "OPENSEARCH_JAVA_OPTS=-Xms512m -Xmx512m" + - VIRTUAL_HOST=$DDEV_HOSTNAME + - HTTP_EXPOSE=9200:9200 + - HTTPS_EXPOSE=9201:9200 + labels: + com.ddev.site-name: ${DDEV_SITENAME} + com.ddev.approot: $DDEV_APPROOT + volumes: + - opensearch:/usr/share/opensearch/data + - ".:/mnt/ddev_config" + - "ddev-global-cache:/mnt/ddev-global-cache" + healthcheck: + test: ["CMD-SHELL", "curl --fail -s localhost:9200"] + + opensearch-dashboards: + image: opensearchproject/opensearch-dashboards:2.11.0 + container_name: 'ddev-${DDEV_SITENAME}-opensearch-dashboards' + environment: + - VIRTUAL_HOST=$DDEV_HOSTNAME + - OPENSEARCH_HOSTS=http://ddev-${DDEV_PROJECT}-opensearch:9200 + - "DISABLE_SECURITY_DASHBOARDS_PLUGIN=true" # disables security plugin + - HTTP_EXPOSE=5601:5601 + - HTTPS_EXPOSE=5602:5601 + expose: + - 5601 + labels: + com.ddev.site-name: ${DDEV_SITENAME} + com.ddev.approot: $DDEV_APPROOT + depends_on: + - opensearch + + web: + depends_on: + - opensearch + +volumes: + opensearch: diff --git a/.ddev/opensearch/Dockerfile b/.ddev/opensearch/Dockerfile new file mode 100644 index 00000000..2b34e444 --- /dev/null +++ b/.ddev/opensearch/Dockerfile @@ -0,0 +1,6 @@ +#ddev-generated +FROM opensearchproject/opensearch:2.11.0 +WORKDIR /usr/share/opensearch + +RUN bin/opensearch-plugin install --batch analysis-phonetic && \ + bin/opensearch-plugin install --batch analysis-icu diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..ca0c2489 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,14 @@ +/.agents/ export-ignore +/.ddev/ export-ignore +/.github/ export-ignore +/.trunk/ export-ignore +/.vscode/ export-ignore +/docs/ export-ignore +/phpstan.neon export-ignore +/mago.toml export-ignore +/CONTRIBUTING.md export-ignore +/context7.json export-ignore +/release-please-config.json export-ignore +/.release-please-manifest.json export-ignore +/skills-lock.json export-ignore +/.trunkignore export-ignore diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 341ee6fc..4a52d610 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -1,136 +1,168 @@ -# GitHub Copilot Instructions for MageForge +# MageForge Copilot Instructions -## Project Overview +## Structure -MageForge is a powerful CLI front-end development toolkit for Magento 2 that simplifies theme development workflows. It provides tools for many types of Magento themes (Magento Standard, Hyvä, Hyvä Fallback, Custom TailwindCSS, Avanta B2B) and can be easily extended for custom themes. +``` +magento/ # Magento 2 installation (DDEV) +src/ + Console/Command # CLI commands (extend AbstractCommand) + Service # Business logic & theme builders + Model # Domain models + etc/di.xml # DI configuration +docs/ # commands.md, custom_theme_builders.md, advanced_usage.md +``` -## Technology Stack +## DDEV -- **Platform**: Magento 2 (requires 2.4.7 or higher) -- **Language**: PHP 8.3+ -- **Package Manager**: Composer -- **Type**: magento2-module -- **Dependencies**: - - Laravel Prompts (for interactive CLI) - - Magento Framework +All Magento CLI commands run via DDEV from the `magento/` directory. Never run `bin/magento` directly. -## Coding Standards +```bash +ddev magento +ddev install-magento # Fresh install +ddev phpcs && ddev phpstan # PHP quality +ddev xdebug on/off +``` -### General PHP Standards +After module changes: `ddev magento setup:upgrade && ddev magento cache:clean` -- **Follow Magento Coding Standards**: All PHP code must adhere to the Magento 2 Coding Standards -- **PSR-4 Autoloading**: The project uses PSR-4 with namespace `OpenForgeProject\MageForge\` -- **Type Declarations**: Use strict typing (`declare(strict_types=1);`) at the top of every PHP file -- **Type Hints**: Always use type hints for parameters and return types -- **Property Promotion**: Use PHP 8+ constructor property promotion with readonly where appropriate -- **Documentation**: Use PHPDoc blocks for classes and methods +## PHP Conventions (PER-CS-2.0 + Magento 2) -### Code Formatting +Every PHP file: -- **Indentation**: Use 4 spaces (not tabs) for indentation -- **Line Length**: Keep lines under 80 characters wherever possible -- **Naming Conventions**: - - Classes: PascalCase - - Methods and properties: camelCase - - Constants: UPPER_SNAKE_CASE - - Choose meaningful names for variables and functions -- **Comments**: Write clear and concise comments where necessary +```php +/Builder.php` implementing `BuilderInterface`: + +```php +public function detect(string $themePath): bool {} // Must be unique per builder +public function build(...): bool {} +public function watch(...): bool {} +public function autoRepair(...): bool {} +public function getName(): string {} +``` + +Register in `src/etc/di.xml` under `BuilderPool`: + +```xml +OpenForgeProject\MageForge\Service\ThemeBuilder\YourType\Builder +``` + +BuilderPool picks the first matching builder — `detect()` must be unique (e.g. check for `hyva-themes.json`). + +## CLI Commands + +Extend `AbstractCommand`, use `executeCommand()`. `$this->io` (SymfonyStyle) is pre-injected. -- **Format**: Use Markdown syntax for all documentation files -- **Location**: Documentation files go in the `docs/` directory -- **README**: Keep README.md updated with new features or commands -- **Comments**: Provide descriptions for functions, classes, and parameters +```php +$this->setName($this->getCommandName('theme', 'build')) + ->setAliases(['m:t:b', 'frontend:build']); +// Return Cli::RETURN_SUCCESS or Cli::RETURN_FAILURE +``` -## Git Workflow +**New command**: update `.github/workflows/magento-compatibility.yml` — add tests (use `--help` or `--dry-run`) to **both** `test-elasticsearch` and `test-opensearch` jobs. -### Commits +## Admin Settings -- **Format**: Use format `# - ` -- **Example**: `#123 - Add support for custom theme builder` -- **Messages**: Write clear, descriptive commit messages -- **VSCode**: Use Git Commit Message Helper extension for proper formatting +When adding an admin config field, all steps must be done together: -### Pull Requests +1. `etc/adminhtml/system.xml` — `` with `translate="label comment"` +2. `etc/config.xml` — default value +3. Config model — `XML_PATH_*` constant +4. Block — getter via `ScopeConfigInterface` +5. Template — pass as `data-*` attribute on Alpine element +6. JavaScript — `this.$el?.getAttribute('data-...')` +7. **`src/i18n/*.csv`** — add label **and** comment string to all locale files -1. Create an issue first to describe the feature/bug -2. Fork the repository and create a branch for your work -3. Make changes with clear commit messages -4. Submit PR to merge into `main` branch -5. Ensure all GitHub Actions checks pass +## Frontend Inspector -## Magento-Specific Guidelines +- Frontend: `src/view/frontend/web/js/inspector.js` +- Backend: `OpenForgeProject\MageForge\Model\TemplateEngine\Decorator\InspectorHints` +- Toggle: `Ctrl+Shift+I` / `Cmd+Option+I` +- Commands: `ddev magento mageforge:theme:inspector enable|disable|status` -- **Module Registration**: Module is registered via `src/registration.php` -- **Commands**: All CLI commands extend `AbstractCommand` and follow Magento command patterns -- **Command Naming**: Use format `mageforge::` (e.g., `mageforge:theme:build`) -- **Shortcodes**: Provide shortcodes for commands (e.g., `m:t:b` for `mageforge:theme:build`) -- **Dependency Injection**: Use Magento's dependency injection container -- **Services**: Service classes should be in the `Service/` directory and follow single responsibility principle +## MageForge Toolbar -## Theme Builder Development +Standalone Alpine.js component (`mageforgeToolbar`), separate from Inspector. -When adding or modifying theme builders: +``` +src/view/frontend/web/js/ + toolbar.js # Entry point + toolbar/ + ui.js # DOM construction + menu.js # toggleMenu/openMenu/closeMenu + feedback.js # showFeedback() toast + audits.js # runAudit() dispatcher + audits/ + index.js # Import & register all audits here +src/view/frontend/web/css/toolbar.css # All styles via --mageforge-* CSS vars +``` -- Implement `BuilderInterface` -- Place builders in `src/Service/ThemeBuilder//Builder.php` -- Register builders with `BuilderPool` -- Support both build and watch modes -- Handle npm/node dependencies appropriately -- Follow existing builder patterns (Magento Standard, Hyvä, TailwindCSS) +Adding an audit: create `toolbar/audits/.js` (export `{ key, icon, label, description, run(context) }`), import and add to array in `audits/index.js`. Menu builds automatically. -## Best Practices +- Events: `mageforge:toolbar:toggle-inspector`, `mageforge:toolbar:inspector-state` +- Never use hardcoded `rgba()` — use `--mageforge-*` CSS variables -- **Error Handling**: Use custom exceptions in the `Exception/` directory -- **Console Output**: Use Symfony Console's IO helpers for consistent output -- **Configuration**: Keep configuration flexible to support different theme types -- **Extensibility**: Design features to be easily extended for custom themes -- **Performance**: Optimize build processes for fast development workflows -- **Compatibility**: Ensure compatibility with Magento 2.4.7+ requirements +## Code Quality -## Common Commands +```bash +ddev phpcs +ddev phpstan +trunk check # actionlint, hadolint, markdownlint, prettier, shellcheck, yamllint +trunk fmt +``` -- `mageforge:theme:list` (or `m:t:l`) - List available themes -- `mageforge:theme:build` (or `m:t:b`) - Build theme CSS/TailwindCSS -- `mageforge:theme:watch` (or `m:t:w`) - Start watch mode for development -- `mageforge:system:check` (or `m:s:c`) - Get system information -- `mageforge:system:version` (or `m:s:v`) - Show version information +Trunk also runs checkov (see `.trunk/trunk.yaml`). -## License +## Git -This project is licensed under GPL-3.0. By contributing, you agree that your work will be licensed under the same terms. +``` +fix/ +feature/ +# - +``` -## Community +## Testing + +Manual after every change: + +1. `ddev magento m:t:l` — theme list +2. `ddev magento m:t:b ` — build +3. `ddev magento m:t:w ` — watch (Ctrl+C) +4. `ddev magento m:s:c` — system check + +CI covers Magento 2.4.7-p10 (PHP 8.3), 2.4.8-p5 (PHP 8.4), and 2.4.9 (PHP 8.5) with OpenSearch. +Theme codes: `Magento/luma`, `Magento/blank`, Hyvä (has `hyva-themes.json`), Custom (has `tailwind.config.js`). + +## Common Pitfalls + +- Shell commands in builders → use `Shell` service (DI), not `exec()` +- After `di.xml` changes → `ddev magento cache:clean` +- `detect()` must be unique — BuilderPool picks first match +- Watch mode blocks terminal +- Node/npm runs in DDEV container, not on host +- New admin settings → always update `src/i18n/*.csv` + +## Documentation -- Report bugs and request features via GitHub Issues -- Start discussions on GitHub Discussions -- Follow the Contributing Guidelines in CONTRIBUTING.md +`docs/` (`commands.md`, `custom_theme_builders.md`, `advanced_usage.md`). Style: DRY, concise, British English. diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..bc7704f3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +# AI Skills +/.agents + +.vscode +/magento/ +/magento-temp/ + +# Trunk - exclude everything except configuration +/.trunk/* +!/.trunk/trunk.yaml +!/.trunk/.gitignore +!/.trunk/configs/ diff --git a/.trunk/.gitignore b/.trunk/.gitignore new file mode 100644 index 00000000..15966d08 --- /dev/null +++ b/.trunk/.gitignore @@ -0,0 +1,9 @@ +*out +*logs +*actions +*notifications +*tools +plugins +user_trunk.yaml +user.yaml +tmp diff --git a/.trunk/configs/.checkov.yaml b/.trunk/configs/.checkov.yaml new file mode 100644 index 00000000..5e123f1c --- /dev/null +++ b/.trunk/configs/.checkov.yaml @@ -0,0 +1,2 @@ +skip-check: + - CKV_DOCKER_7 diff --git a/.trunk/configs/.hadolint.yaml b/.trunk/configs/.hadolint.yaml new file mode 100644 index 00000000..37b7d2d7 --- /dev/null +++ b/.trunk/configs/.hadolint.yaml @@ -0,0 +1,5 @@ +# Following source doesn't work in most setups +ignored: + - SC1090 + - SC1091 + - DL3007 diff --git a/.trunk/configs/.markdownlint.yaml b/.trunk/configs/.markdownlint.yaml new file mode 100644 index 00000000..b40ee9d7 --- /dev/null +++ b/.trunk/configs/.markdownlint.yaml @@ -0,0 +1,2 @@ +# Prettier friendly markdownlint config (all formatting rules disabled) +extends: markdownlint/style/prettier diff --git a/.trunk/configs/.shellcheckrc b/.trunk/configs/.shellcheckrc new file mode 100644 index 00000000..8c7b1ada --- /dev/null +++ b/.trunk/configs/.shellcheckrc @@ -0,0 +1,7 @@ +enable=all +source-path=SCRIPTDIR +disable=SC2154 + +# If you're having issues with shellcheck following source, disable the errors via: +# disable=SC1090 +# disable=SC1091 diff --git a/.trunk/configs/.yamllint.yaml b/.trunk/configs/.yamllint.yaml new file mode 100644 index 00000000..184e251f --- /dev/null +++ b/.trunk/configs/.yamllint.yaml @@ -0,0 +1,7 @@ +rules: + quoted-strings: + required: only-when-needed + extra-allowed: ["{|}"] + key-duplicates: {} + octal-values: + forbid-implicit-octal: true diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml new file mode 100644 index 00000000..b0fc6613 --- /dev/null +++ b/.trunk/trunk.yaml @@ -0,0 +1,42 @@ +# This file controls the behavior of Trunk: https://docs.trunk.io/cli +# To learn more about the format of this file, see https://docs.trunk.io/reference/trunk-yaml +version: 0.1 +cli: + version: 1.25.0 +# Trunk provides extensibility via plugins. (https://docs.trunk.io/plugins) +plugins: + sources: + - id: trunk + ref: v1.7.4 + uri: https://github.com/trunk-io/plugins +# Many linters and tools depend on runtimes - configure them here. (https://docs.trunk.io/runtimes) +runtimes: + enabled: + - go@1.21.0 + - node@22.16.0 + - python@3.10.8 +# This is the section where you manage your linters. (https://docs.trunk.io/check/configuration) +lint: + ignore: + - linters: [yamllint, prettier] + paths: + - .ddev/** + enabled: + - checkov@3.2.499 + - actionlint@1.7.10 + - git-diff-check + - hadolint@2.14.0 + - markdownlint@0.47.0 + - oxipng@10.1.0 + - prettier@3.8.1 + - shellcheck@0.11.0 + - shfmt@3.6.0 + - trufflehog@3.92.5 + - yamllint@1.38.0 +actions: + disabled: + - trunk-check-pre-push + - trunk-fmt-pre-commit + enabled: + - trunk-announce + - trunk-upgrade-available diff --git a/.trunkignore b/.trunkignore new file mode 100644 index 00000000..5acee863 --- /dev/null +++ b/.trunkignore @@ -0,0 +1,2 @@ +# Trunk ignore patterns +.ddev/** diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 441891a4..f5432648 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,6 +2,8 @@ We appreciate your interest in contributing to MageForge! Please follow the guidelines below to ensure a smooth and effective contribution process. +> **New here?** Start with the [Development Guide](./docs/development.md) to set up your local DDEV environment before making any changes. + ## Submitting a Pull Request 1. **Create an Issue**: Start by [creating an issue](https://github.com/OpenForgeProject/mageforge/issues) to describe your feature request or bug report. Be sure to include all relevant details. diff --git a/README.md b/README.md index 01a144a8..22440bdc 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,8 @@ MageForge is a powerful CLI front-end development toolkit for Magento 2 that sim - [Project Information](#project-information) - [Credits](#credits) +> **Contributor?** Jump straight to the [Development Guide](./docs/development.md) for DDEV setup, workflow, and coding standards. + ## Supported Magento Versions MageForge requires Magento 2.4.7 or higher with PHP 8.3 or higher. @@ -146,9 +148,10 @@ bin/magento mageforge:theme:inspector disable ## Additional Documentation +- [Commands Documentation](./docs/commands.md) - Detailed command reference - [Advanced Usage Guide](./docs/advanced_usage.md) - Tips, tricks and troubleshooting - [Custom Theme Builders Documentation](./docs/custom_theme_builders.md) - Extend MageForge for your custom themes -- [Commands Documentation](./docs/commands.md) - Detailed command reference +- [Development Guide](./docs/development.md) - Local dev environment setup, workflows, and contribution guide ## Support @@ -156,6 +159,8 @@ bin/magento mageforge:theme:inspector disable - **Discussions**: [GitHub Discussions](https://github.com/OpenForgeProject/mageforge/discussions) - **Contributing**: See [Contributing Guidelines](./CONTRIBUTING.md) +> **Want to contribute?** Check out the [Development Guide](./docs/development.md) for environment setup, workflow, and coding standards. + ## Project Information - **License**: [LICENSE](LICENSE) diff --git a/docs/development.md b/docs/development.md new file mode 100644 index 00000000..ea23df2f --- /dev/null +++ b/docs/development.md @@ -0,0 +1,236 @@ +# MageForge Development Environment + +Welcome to the MageForge development repository. This guide covers everything you need to set up a local development environment and contribute to the module. + +## Table of Contents + +- [Repository Structure](#repository-structure) +- [Prerequisites](#prerequisites) +- [Initial Setup](#initial-setup) +- [Development Workflow](#development-workflow) +- [Code Quality](#code-quality) +- [Common Issues](#common-issues) +- [Building a Release](#building-a-release) + +--- + +## Repository Structure + +``` +/mageforge +├── /src/ # ⭐ The MageForge module code +│ ├── /Console/Command/ # CLI commands +│ ├── /Service/ # Business logic & theme builders +│ ├── /Model/ # Domain models +│ ├── /etc/ # Module configuration (di.xml, module.xml, …) +│ ├── /view/ # Frontend assets & templates +│ └── /i18n/ # Localisation files +│ +├── /magento/ # Local Magento 2 installation (testing only) +│ ├── /app/design/ # Test themes +│ ├── /vendor/ # Magento & dependencies +│ └── /bin/magento # Magento CLI +│ +├── /.ddev/ # DDEV configuration +│ └── /commands/web/ # Custom DDEV web-container commands +│ +├── /docs/ # Documentation (you are here) +├── CONTRIBUTING.md # Contribution guidelines & commit conventions +└── README.md # End-user documentation (install, features) +``` + +> **Key points** +> +> - All module development happens in `/src/` — this is where you write code. +> - Testing happens in `/magento/` — a full Magento 2 installation wired up for local use. +> - `/src/` is symlinked into `/magento/vendor/openforgeproject/mageforge/` during installation, so changes are reflected instantly. +> - `/magento/` is never included in a release. It exists solely for local development. + +--- + +## Prerequisites + +| Tool | Notes | +| ---- | ----- | +| [DDEV](https://ddev.readthedocs.io/en/stable/users/install/ddev-installation/) | v1.23 or higher recommended | +| Git | For cloning and branching | +| Docker | Required by DDEV | + +Basic familiarity with Magento 2 module development is assumed. + +--- + +## Initial Setup + +1. **Clone the repository:** + + ```bash + git clone git@github.com:OpenForgeProject/mageforge.git + cd mageforge + ``` + +2. **Start DDEV** (pulls containers, configures the environment): + + ```bash + ddev start + ``` + +3. **Install Magento 2:** + + ```bash + ddev install-magento + ``` + + This script will: + - Install a fresh Magento 2 instance inside `/magento/` + - Install Magento sample data + - Register `/src/` as a Composer path repository and `require` it (creates a symlink at `/magento/vendor/openforgeproject/mageforge/`) + - Enable and register the MageForge module + - Set developer mode and disable 2FA + +4. **Verify the installation:** + + ```bash + ddev magento mageforge:system:check + ``` + +You now have a fully functional local development environment. + +--- + +## Development Workflow + +### Making Changes + +1. Edit code in `/src/` (commands, services, builders, etc.) +2. Apply changes to Magento: + + ```bash + ddev magento setup:upgrade # Register module updates + ddev magento cache:clean # Clear application cache + ``` + +3. Test your changes: + + ```bash + ddev magento mageforge:theme:list # List all themes + ddev magento mageforge:theme:build # Build a theme + ddev magento mageforge:theme:watch # Watch mode (Ctrl+C to stop) + ddev magento mageforge:system:check # System diagnostics + ``` + +### Useful DDEV Commands + +```bash +ddev magento # Run any Magento CLI command inside the container +ddev ssh # Open a shell inside the container +ddev xdebug on/off # Toggle Xdebug (VS Code tasks also available) +ddev logs # Tail container logs +ddev restart # Restart all containers +``` + +### Running Tests Manually + +```bash +# Theme detection +ddev magento mageforge:theme:list + +# Standard Magento build +ddev magento mageforge:theme:build Magento/luma + +# Hyvä theme build (requires Hyvä to be installed) +ddev magento mageforge:theme:build Hyva/default + +# Watch mode +ddev magento mageforge:theme:watch Magento/luma + +# System diagnostics +ddev magento mageforge:system:check +``` + +CI runs the following matrix against OpenSearch — test locally before opening a PR: + +| Magento | PHP | +| ------- | --- | +| 2.4.7-p10 | 8.3 | +| 2.4.8-p5 | 8.4 | +| 2.4.9 | 8.5 | + +--- + +## Code Quality + +Run all checks before submitting a pull request: + +```bash +# All linters (actionlint, hadolint, markdownlint, prettier, shellcheck, yamllint) +trunk check + +# Auto-format +trunk fmt + +# PHP CodeSniffer – Magento Coding Standard +ddev phpcs + +# PHPStan – static analysis +ddev phpstan +``` + +### PHP Conventions + +- `declare(strict_types=1)` in every PHP file +- Constructor property promotion with `readonly` +- Native type hints only — no FQNs in docblocks +- Named arguments when a function takes many parameters +- Enums over constants (PHP 8.3+) + +For full details see [CONTRIBUTING.md](../CONTRIBUTING.md). + +### Soft Dependencies (Hyvä Compatibility) + +MageForge must work **with and without** Hyvä installed. Never add hard type-hints on optional third-party classes in constructors. Use `mixed` + `class_exists()` for optional dependencies and inline `@var` annotations for PHPStan. + +--- + +## Common Issues + +**Module not found after changes:** + +```bash +ddev magento setup:upgrade && ddev magento cache:clean +``` + +**DDEV not starting:** + +```bash +ddev poweroff +ddev start +``` + +**Need to reinstall Magento from scratch:** + +```bash +ddev install-magento # Handles cleanup automatically +``` + +**`detect()` returns wrong builder:** + +Each builder's `detect()` method must uniquely identify its theme type. The `BuilderPool` picks the _first_ matching builder, so overlapping detection logic causes unpredictable results. + +**Shell commands in builders:** + +Always use the `Shell` service via dependency injection — never call `exec()` or `shell_exec()` directly. + +--- + +## Building a Release + +The module in `/src/` is what gets packaged and published to Packagist. End users install it via: + +```bash +composer require openforgeproject/mageforge +``` + +Releases are automated via [Release Please](https://github.com/googleapis/release-please). When a PR is merged into `main` with a valid [Conventional Commits](https://www.conventionalcommits.org/) title, Release Please opens a release PR that bumps the version and updates the changelog. Merging that PR triggers the release. + +The `/magento/` directory is excluded from all release artefacts.