null, - Will compile all languages from {{static_content_locales}} for Magento/luma // 'Custom/theme' => 'en_US fr_FR' - Will compile only en_US and fr_FR for Custom/theme // 'Custom/another' => '{{static_content_locales}} it_IT' - Will compile all languages from {{static_content_locales}} + it_IT for Custom/another // ]); - Will compile this theme with every language set('magento_themes', [ ]); // Static content deployment options, e.g. '--no-parent' set('static_deploy_options', ''); // Deploy frontend and adminhtml together as default set('split_static_deployment', false); // Use the default languages for the backend as default set('static_content_locales_backend', '{{static_content_locales}}'); // backend themes to deploy. Only used if split_static_deployment=true // This setting supports the same options/structure as {{magento_themes}} set('magento_themes_backend', ['Magento/backend' => null]); // Configuration // Also set the number of concurrent jobs to run. The default is 1 // Update using: `set('static_content_jobs', '1');` set('static_content_jobs', '1'); set('content_version', function () { return time(); }); // Magento directory relative to repository root. Use "." (default) if it is not located in a subdirectory set('magento_dir', '.'); set('shared_files', [ '{{magento_dir}}/app/etc/env.php', '{{magento_dir}}/var/.maintenance.ip', ]); set('shared_dirs', [ '{{magento_dir}}/var/composer_home', '{{magento_dir}}/var/log', '{{magento_dir}}/var/export', '{{magento_dir}}/var/report', '{{magento_dir}}/var/import', '{{magento_dir}}/var/import_history', '{{magento_dir}}/var/session', '{{magento_dir}}/var/importexport', '{{magento_dir}}/var/backups', '{{magento_dir}}/var/tmp', '{{magento_dir}}/pub/sitemap', '{{magento_dir}}/pub/media', '{{magento_dir}}/pub/static/_cache' ]); set('writable_dirs', [ '{{magento_dir}}/var', '{{magento_dir}}/pub/static', '{{magento_dir}}/pub/media', '{{magento_dir}}/generated', '{{magento_dir}}/var/page_cache' ]); set('clear_paths', [ '{{magento_dir}}/generated/*', '{{magento_dir}}/pub/static/_cache/*', '{{magento_dir}}/var/generation/*', '{{magento_dir}}/var/cache/*', '{{magento_dir}}/var/page_cache/*', '{{magento_dir}}/var/view_preprocessed/*' ]); set('bin/magento', '{{release_or_current_path}}/{{magento_dir}}/bin/magento'); set('magento_version', function () { // detect version $versionOutput = run('{{bin/php}} {{bin/magento}} --version'); preg_match('/(\d+\.?)+(-p\d+)?$/', $versionOutput, $matches); return $matches[0] ?? '2.0'; }); set('config_import_needed', function () { // detect if app:config:import is needed try { run('{{bin/php}} {{bin/magento}} app:config:status'); } catch (RunException $e) { if ($e->getExitCode() == CONFIG_IMPORT_NEEDED_EXIT_CODE) { return true; } throw $e; } return false; }); set('database_upgrade_needed', function () { // detect if setup:upgrade is needed try { run('{{bin/php}} {{bin/magento}} setup:db:status'); } catch (RunException $e) { if ($e->getExitCode() == DB_UPDATE_NEEDED_EXIT_CODE) { return true; } throw $e; } try { run('{{bin/php}} {{bin/magento}} module:config:status'); } catch (RunException $e) { if ($e->getExitCode() == CONFIG_PHP_UPDATE_NEEDED_EXIT_CODE) { return true; } throw $e; } return false; }); // Deploy without setting maintenance mode if possible set('enable_zerodowntime', true); // Tasks // To work correctly with artifact deployment, it is necessary to set the MAGE_MODE correctly in `app/etc/config.php` // e.g. // ```php // 'MAGE_MODE' => 'production' // ``` desc('Compiles magento di'); task('magento:compile', function () { run("{{bin/php}} {{bin/magento}} setup:di:compile"); run('cd {{release_or_current_path}}/{{magento_dir}} && {{bin/composer}} dump-autoload -o'); }); // To work correctly with artifact deployment it is necessary to set `system/dev/js` , `system/dev/css` and `system/dev/template` // in `app/etc/config.php`, e.g.: // ```php // 'system' => [ // 'default' => [ // 'dev' => [ // 'js' => [ // 'merge_files' => '1', // 'minify_files' => '1' // ], // 'css' => [ // 'merge_files' => '1', // 'minify_files' => '1' // ], // 'template' => [ // 'minify_html' => '1' // ] // ] // ] // ``` desc('Deploys assets'); task('magento:deploy:assets', function () { $themesToCompile = ''; if (get('split_static_deployment')) { invoke('magento:deploy:assets:adminhtml'); invoke('magento:deploy:assets:frontend'); } else { if (count(get('magento_themes')) > 0 ) { $themes = array_is_list(get('magento_themes')) ? get('magento_themes') : array_keys(get('magento_themes')); foreach ($themes as $theme) { $themesToCompile .= ' -t ' . $theme; } } run("{{bin/php}} {{release_or_current_path}}/bin/magento setup:static-content:deploy -f --content-version={{content_version}} {{static_deploy_options}} {{static_content_locales}} $themesToCompile -j {{static_content_jobs}}"); } }); desc('Deploys assets for backend only'); task('magento:deploy:assets:adminhtml', function () { magentoDeployAssetsSplit('backend'); }); desc('Deploys assets for frontend only'); task('magento:deploy:assets:frontend', function () { magentoDeployAssetsSplit('frontend'); }); /** * @phpstan-param 'frontend'|'backend' $area * * @throws ConfigurationException */ function magentoDeployAssetsSplit(string $area) { if (!in_array($area, ['frontend', 'backend'], true)) { throw new ConfigurationException("\$area must be either 'frontend' or 'backend', '$area' given"); } $isFrontend = $area === 'frontend'; $suffix = $isFrontend ? '' : '_backend'; $themesConfig = get("magento_themes$suffix"); $defaultLanguages = get("static_content_locales$suffix"); $useDefaultLanguages = array_is_list($themesConfig); /** @var list $themes */ $themes = $useDefaultLanguages ? array_values($themesConfig) : array_keys($themesConfig); $staticContentArea = $isFrontend ? 'frontend' : 'adminhtml'; if ($useDefaultLanguages) { $themes = '-t '.implode(' -t ', $themes); run("{{bin/php}} {{bin/magento}} setup:static-content:deploy -f --area=$staticContentArea --content-version={{content_version}} {{static_deploy_options}} $defaultLanguages $themes -j {{static_content_jobs}}"); return; } foreach ($themes as $theme) { $languages = parse($themesConfig[$theme] ?? $defaultLanguages); run("{{bin/php}} {{bin/magento}} setup:static-content:deploy -f --area=$staticContentArea --content-version={{content_version}} {{static_deploy_options}} $languages -t $theme -j {{static_content_jobs}}"); } } desc('Syncs content version'); task('magento:sync:content_version', function () { $timestamp = time(); on(select('all'), function (Host $host) use ($timestamp) { $host->set('content_version', $timestamp); }); })->once(); before('magento:deploy:assets', 'magento:sync:content_version'); desc('Enables maintenance mode'); task('magento:maintenance:enable', function () { // do not use {{bin/magento}} because it would be in "release" but the maintenance mode must be set in "current" run("if [ -d $(echo {{current_path}}) ]; then {{bin/php}} {{current_path}}/{{magento_dir}}/bin/magento maintenance:enable; fi"); }); desc('Disables maintenance mode'); task('magento:maintenance:disable', function () { // do not use {{bin/magento}} because it would be in "release" but the maintenance mode must be set in "current" run("if [ -d $(echo {{current_path}}) ]; then {{bin/php}} {{current_path}}/{{magento_dir}}/bin/magento maintenance:disable; fi"); }); desc('Set maintenance mode if needed'); task('magento:maintenance:enable-if-needed', function () { ! get('enable_zerodowntime') || get('database_upgrade_needed') || get('config_import_needed') ? invoke('magento:maintenance:enable') : writeln('Config and database up to date => no maintenance mode'); }); desc('Config Import'); task('magento:config:import', function () { if (get('config_import_needed')) { run('{{bin/php}} {{bin/magento}} app:config:import --no-interaction'); } else { writeln('App config is up to date => import skipped'); } }); desc('Upgrades magento database'); task('magento:upgrade:db', function () { if (get('database_upgrade_needed')) { run("{{bin/php}} {{bin/magento}} setup:db-schema:upgrade --no-interaction"); run("{{bin/php}} {{bin/magento}} setup:db-data:upgrade --no-interaction"); } else { writeln('Database schema is up to date => upgrade skipped'); } })->once(); desc('Flushes Magento Cache'); task('magento:cache:flush', function () { run("{{bin/php}} {{bin/magento}} cache:flush"); }); desc('Magento2 deployment operations'); task('deploy:magento', [ 'magento:build', 'magento:maintenance:enable-if-needed', 'magento:config:import', 'magento:upgrade:db', 'magento:maintenance:disable', 'magento:cache:flush', ]); desc('Magento2 build operations'); task('magento:build', [ 'magento:compile', 'magento:deploy:assets', ]); desc('Deploys your project'); task('deploy', [ 'deploy:prepare', 'deploy:vendors', 'deploy:clear_paths', 'deploy:magento', 'deploy:publish', ]); after('deploy:failed', 'magento:maintenance:disable'); // Artifact deployment section // The file the artifact is saved to set('artifact_file', 'artifact.tar.gz'); // The directory the artifact is saved in set('artifact_dir', 'artifacts'); // Points to a file with a list of files to exclude from packaging. // The format is as with the `tar --exclude-from=[file]` option set('artifact_excludes_file', 'artifacts/excludes'); // If set to true, the artifact is built from a clean copy of the project repository instead of the current working directory set('build_from_repo', false); // Set this value if "build_from_repo" is set to true. The target to deploy must also be set with "--branch", "--tag" or "--revision" set('repository', null); // The relative path to the artifact file. If the directory does not exist, it will be created set('artifact_path', function () { if (!testLocally('[ -d {{artifact_dir}} ]')) { runLocally('mkdir -p {{artifact_dir}}'); } return get('artifact_dir') . '/' . get('artifact_file'); }); // The location of the tar command. On MacOS you should have installed gtar, as it supports the required settings set('bin/tar', function () { if (commandExist('gtar')) { return which('gtar'); } else { return which('tar'); } }); // tasks section desc('Packages all relevant files in an artifact.'); task('artifact:package', function() { if (!test('[ -f {{artifact_excludes_file}} ]')) { throw new GracefulShutdownException( "No artifact excludes file provided, provide one at artifacts/excludes or change location" ); } run('{{bin/tar}} --exclude-from={{artifact_excludes_file}} -czf {{artifact_path}} -C {{release_or_current_path}} .'); }); desc('Uploads artifact in release folder for extraction.'); task('artifact:upload', function () { upload(get('artifact_path'), '{{release_path}}'); }); desc('Extracts artifact in release path.'); task('artifact:extract', function () { run('{{bin/tar}} -xzpf {{release_path}}/{{artifact_file}} -C {{release_path}}'); run('rm -rf {{release_path}}/{{artifact_file}}'); }); desc('Clears generated files prior to building.'); task('build:remove-generated', function() { run('rm -rf generated/*'); }); desc('Prepare local artifact build'); task('build:prepare', function() { if (!currentHost()->get('local')) { throw new GracefulShutdownException('Artifact can only be built locally, you provided a non local host'); } $buildDir = get('build_from_repo') ? get('artifact_dir') . '/repo' : '.'; set('deploy_path', $buildDir); set('release_path', $buildDir); set('current_path', $buildDir); if (!get('build_from_repo')) { return; } $repository = (string) get('repository'); if ($repository === '') { throw new GracefulShutdownException('You must specify the "repository" option.'); } run('rm -rf {{release_or_current_path}}'); run('git clone {{repository}} {{release_or_current_path}}'); run('git -C {{release_or_current_path}} checkout --force {{target}}'); }); desc('Builds an artifact.'); task('artifact:build', [ 'build:prepare', 'build:remove-generated', 'deploy:vendors', 'magento:compile', 'magento:deploy:assets', 'artifact:package', ]); // Array of shared files that will be added to the default shared_files without overriding set('additional_shared_files', []); // Array of shared directories that will be added to the default shared_dirs without overriding set('additional_shared_dirs', []); desc('Adds additional files and dirs to the list of shared files and dirs'); task('deploy:additional-shared', function () { add('shared_files', get('additional_shared_files')); add('shared_dirs', get('additional_shared_dirs')); }); /** * Update cache id_prefix on deploy so that you are compiling against a fresh cache * Reference Issue: https://github.com/davidalger/capistrano-magento2/issues/151 * To use this feature, add the following to your deployer scripts: * ```php * after('deploy:shared', 'magento:set_cache_prefix'); * after('deploy:magento', 'magento:cleanup_cache_prefix'); * ``` **/ desc('Update cache id_prefix'); task('magento:set_cache_prefix', function () { //download current env config $tmpConfigFile = tempnam(sys_get_temp_dir(), 'deployer_config'); download('{{deploy_path}}/shared/' . ENV_CONFIG_FILE_PATH, $tmpConfigFile); $envConfigArray = include($tmpConfigFile); //set prefix to `alias_releasename_` $prefixUpdate = get('alias') . '_' . get('release_name') . '_'; //check for preload keys and update if (isset($envConfigArray['cache']['frontend']['default']['backend_options']['preload_keys'])) { $oldPrefix = $envConfigArray['cache']['frontend']['default']['id_prefix']; $preloadKeys = $envConfigArray['cache']['frontend']['default']['backend_options']['preload_keys']; $newPreloadKeys = []; foreach ($preloadKeys as $preloadKey) { $newPreloadKeys[] = preg_replace('/^' . $oldPrefix . '/', $prefixUpdate, $preloadKey); } $envConfigArray['cache']['frontend']['default']['backend_options']['preload_keys'] = $newPreloadKeys; } //update id_prefix to include release name $envConfigArray['cache']['frontend']['default']['id_prefix'] = $prefixUpdate; $envConfigArray['cache']['frontend']['page_cache']['id_prefix'] = $prefixUpdate; //Generate configuration array as string $envConfigStr = '