├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── Gemfile ├── LICENSE.md ├── README.md ├── Rakefile ├── capistrano-magento2.gemspec └── lib ├── capistrano-magento2.rb └── capistrano ├── magento2.rb ├── magento2 ├── cachetool.rb ├── defaults.rb ├── deploy.rb ├── notifier.rb ├── pending.rb └── version.rb └── tasks ├── cachetool.rake ├── deploy.rake ├── magento.rake ├── notifier.rake └── pending.rake /.gitignore: -------------------------------------------------------------------------------- 1 | /.bundle/ 2 | /.yardoc 3 | /Gemfile.lock 4 | /_yardoc/ 5 | /coverage/ 6 | /doc/ 7 | /pkg/ 8 | /spec/reports/ 9 | /tmp/ 10 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | rvm: 3 | 2.4 4 | 5 | before_install: 6 | - gem update --system 7 | - gem install bundler 8 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Capistrano::Magento2 Change Log 2 | 3 | 0.9.4 4 | ========= 5 | 6 | * Updated to now set SELinux context on `var` directory with default type of `httpd_sys_rw_content_t` to allow application writes where SELinux is enabled. 7 | 8 | 0.9.3 9 | ========= 10 | 11 | * Updated to now specify `--non-interactive` flag on `app:config:import` so CLI command will not hang trying for user input. 12 | 13 | 0.9.2 14 | ========= 15 | 16 | * Fixed issue preventing use of `after` tasks on `magento:cache:flush` from being used to trigger service reloads at end of deployment ([issue #143](https://github.com/davidalger/capistrano-magento2/issues/143)) 17 | * Updated to use DSL method `invoke!` to call iterant tasks ([see capistrano/capistrano/pull/1911](https://github.com/capistrano/capistrano/pull/1911))) 18 | 19 | 0.9.1 20 | ========= 21 | 22 | * Fixed regression in 0.9.0 where relying on the `-l` flag broke multilingual static content deployment ([issue #141](https://github.com/davidalger/capistrano-magento2/issues/141)) 23 | 24 | 0.9.0 25 | ========= 26 | 27 | **Upgrade Notes:** 28 | 29 | As of this release only Magento 2.3 and later are supported and **support has been dropped for prior versions** which have long since reached their end-of-life. Moving forward versions past their EOL will no longer be supported by subsequent releases of this gem. Older versions of this gem may continue to be used to deploy older and EOL versions. 30 | 31 | If using a `Gemfile` with Bundler to lock versions of dependencies used for execution, the version lock on `capistrano` should be updated to `~>1.13` to match the minimal requirement of this release, otherwise `bundle update` will fail to update to version `0.9.0` of this gem. The following is recommended: 32 | 33 | ``` 34 | gem 'capistrano', '~> 3.14' 35 | gem 'capistrano-magento2', '~> 0.9' 36 | ``` 37 | 38 | If a capistrano version lock is present in a projects `deploy.rb` it will also need to be updated: 39 | 40 | ``` 41 | lock '~> 3.14' 42 | ``` 43 | 44 | **Change Summary:** 45 | 46 | * Dropped support for EOL versions of Magento and scrubbed all gated logic around legacy behaviors in 2.1.x and 2.2.x 47 | * Removed `magento:deploy:version_check` task and associated warning when attempting to deploy unsupported versions of Magento 48 | * Updated required version of `capistrano` to `~> 1.13` (>=1.13 and less than 2.0) 49 | * Resolved inability to use `--dry-run` flag ([issue #128](https://github.com/davidalger/capistrano-magento2/issues/128)) as made possible by the removal of all version related gating logic. 50 | * Dropped explicit default of `:magento_deploy_languages`; will now only be passed to `bin/magento` call when set in project configuration. 51 | * Updated zero-down deployment logic to rely on `app:config:status` to detect config changes rather than the md5sum of config.php in current and release directories. 52 | * Added `magento:app:config:status` to available commands for manual execution. 53 | * Fixes issue in 2.3.4 and later where app:config:import may fail if cache:flush is not run immediately prior ([issue #138](https://github.com/davidalger/capistrano-magento2/issues/138)) 54 | 55 | 0.8.9 56 | ========= 57 | 58 | * Fixed issue with RabbitMQ settings caused by app:config:import running after setup-upgrade step vs prior to the database upgrades (which connects to RabbitMQ in recurring data upgrade scripts) 59 | 60 | 0.8.8 61 | ========== 62 | 63 | * Added support for zero-side-effect pipeline deployments when scopes/themes have been dumped to config.php 64 | 65 | 0.8.7 66 | ========== 67 | 68 | * Updated use of `touch` to run such that SSHKit prefixes may be used (PR #110) 69 | 70 | 0.8.6 71 | ========== 72 | 73 | * Fixed possible race condition in `magento:deploy:version_check` when `app/etc/env.php` resides on an NFS share 74 | 75 | 0.8.5 76 | ========== 77 | 78 | * Added ability to override flags sent to `composer install` to workaround issue in Magento 2.3 beta preventing deploy 79 | 80 | 0.8.4 81 | ========== 82 | 83 | * Disabled call to `magento:setup:db:schema:upgrade` when running a zero-down deployment 84 | * Disabled call to `magento:setup:db:data:upgrade` when running a zero-down deployment 85 | * Fixed possible race condition in `magento:deploy:mode:production` when `app/etc/env.php` resides on an NFS share 86 | 87 | 0.8.3 88 | ========== 89 | 90 | * Fixed regression failing deployment when `:magento_deploy_composer` is set to `false` (PR #106) 91 | 92 | 0.8.2 93 | ========== 94 | 95 | * Added `var/export` to default list of :linked_dirs to support bundled `dotmailer/dotmailer-magento2-extension` package 96 | 97 | 0.8.1 98 | ========== 99 | 100 | * Added `require 'capistrano/magento2/cachetool'` which may be used to enable flushing the php-opcache when [cachetool](http://gordalina.github.io/cachetool/) is installed on the server 101 | * Added `cachetool:opcache:status` and `cachetool:opcache:reset` commands (use `require 'capistrano/magento2/cachetool'` to enable them) 102 | * Fixed issue causing deployment to disable maintenance mode when manually enabled prior to deployment (issue #16) 103 | 104 | 0.8.0 105 | ========== 106 | 107 | * Added support for zero-down deployment (PR #104, issue #34) 108 | * Added call to "composer dump-autoload --no-dev --optimize" following DI compliation (issue #102) 109 | 110 | 0.7.3 111 | ========== 112 | 113 | * Optimized set permissions operation (PR #89) 114 | * Fixed `uninitialized constant Capistrano::Magento2::Setup::DateTime` error (PR #93, issue #92) 115 | 116 | 0.7.2 117 | ========== 118 | 119 | * Added support for Magento 2.2 [static content deploy strategies](http://bit.ly/2yhMvVv) (PR #85) 120 | * Added support for Magento 2.2 [shared application config files](http://bit.ly/2gF8Ouu) (issue #83) 121 | 122 | 0.7.1 123 | ========== 124 | 125 | * Fixed deploy routine so production mode is no longer enabled automatically when `:magento_deploy_production` is false 126 | * Fixed regression in multi-lingual deployment (reverted boxing workaround with 2.1.7 upper limit; release notes are wrong and the issue persists in 2.1.8) 127 | * Updated double run of static content deploy to only apply to versions prior to 2.1.8 (underling issue was resolved in 2.1.8) 128 | 129 | 0.7.0 130 | ========== 131 | 132 | * Added support for Magento 2.2.0 release candidates 133 | * Removed support for deployment of Magento versions older than 2.1.1 134 | * Updated and optimized static content deployment for upcoming Magento 2.2.0 release 135 | * Updated composer install routine; --no-dev is now used indiscriminately since Magento 2.1.1 and later support it; no more duplicate composer install commands (issue #76) 136 | * Updated multi-lingual site deployment workaround to apply only to versions 2.1.3 through 2.1.7 as per 2.1.8 release notes the underlying issue has been resolved (issue #72) 137 | * Added tasks to set production mode and show current mode (magento:deploy:mode:production and magento:deploy:mode:show) 138 | 139 | 0.6.6 140 | ========== 141 | 142 | * Updated date formatting of pending change log output for enhanced readability (PR #73) 143 | * Fixed bug in static content deploy resulting from a change in behaviour in Magento 2.1.3 and later (PR #74) 144 | 145 | 0.6.5 146 | ========== 147 | 148 | * Added workaround for Magento 2.1.3 bug causing multi-lingual static-content deployment failure (issue #72) 149 | 150 | 0.6.4 151 | ========== 152 | 153 | * Added support for the config.local.php file found in Magento 2.1.6 and later 154 | 155 | 0.6.3 156 | ========== 157 | 158 | * Fixed deployment to multiple hosts resulting in disparate static content versions across target hosts 159 | 160 | 0.6.2 161 | ========== 162 | 163 | * Added setting `:magento_deploy_jobs` to support configuring number of parallel static content deployment tasks 164 | * Fixed issue where ./update dir may exist without a composer.json file, causing deployment failure 165 | * Updated uses of bin/magento where output is parsed to include `--no-ansi` to eliminate potential failures 166 | * Improved error reporting on static content deployment failure 167 | 168 | 0.6.1 169 | ========== 170 | 171 | * Fixed Magento version check failing on some servers due to ansi output in non-interactive shells (issue #64) 172 | * Added ability to configure Magento's composer authentication keys. See README for details (PR #56) 173 | * Changed pending change log to hook into before `deploy:check` (previously hooked before `deploy`) 174 | 175 | 0.6.0 176 | ========== 177 | 178 | * Added full-featured pending change logging functionality. See README for details (issue #58) 179 | * Fixed inability to set PATH in capistrano configuration vs `.bashrc` file (issue #62) 180 | * Updated README to reflect removing the `terminal-notifier` gem as a hard dependency (issue #19) 181 | * Removed `capistrano-pending` as a dependency (issue #58) 182 | 183 | 0.5.9 184 | ========== 185 | 186 | * Updated README with Capistrano 3.7 setup information 187 | * Updated `linked_dirs` to link `pub/sitemaps` by default in similar fashion to the Magento1 deployment gem 188 | * Updated README with guidance on adding a path to the list of `linked_dirs` without copying the entire configuration forward 189 | * Fixed bug causing pipefail option to persist after `Capistrano::Magento2::Setup.static_content_deploy` is called 190 | 191 | 0.5.8 192 | ========== 193 | 194 | * Fixed critical failure due to command map being broken in v0.5.7 updates (issue #50, issue #51) 195 | 196 | 0.5.7 197 | ========== 198 | _Note: This release was yanked from RubyGems due to a critical failure in the deploy routine._ 199 | 200 | * Fixed failing deploys for Magento 2.1.0 caused by improper version checks on flags added in version 2.1.1 (issue #45) 201 | * Fixed failure to detect error codes Magento 2.1.1 returns on a failed static-content deploy job (issue #44) 202 | 203 | 0.5.6 204 | ========== 205 | 206 | * Fixed issue where setup:di:compile failing to return an exit code caused DI compilation failures to be masked (issue #41) 207 | 208 | 0.5.5 209 | ========== 210 | 211 | * Fixed DI artifact mismatch caused by setup:ugprade overwriting frozen config.php post compilation 212 | * Removed redundant (and non-functional) commands from deploy:reverted task 213 | * Added informational output which lists the installed modules which are disabled per `app/etc/config.php` 214 | 215 | 0.5.4 216 | ========== 217 | 218 | * Fixed issue causing failed releases when there are CSS compilation errors in setup:static-content:deploy task 219 | * Updated static content deployment to ignore `:magento_deploy_themes` when deploying 2.0 and issue a warning message. 220 | 221 | 0.5.3 222 | ========== 223 | 224 | * Added setting `:magento_deploy_cache_shared` for targeting cache related tasks (issue #33) 225 | * Added setting `:magento_deploy_setup_role` for targeting setup related tasks (issue #33) 226 | * Fixed magento setup, cache, index commands to only run on appropriate node(s) in multi-node deploys (issue #33). 227 | * Fixed capistrano-pending support to play nicely with multiple hosts. Now only performs check on a single host. 228 | * Updated `magento:deploy:verify` output with host specific messaging on configuration errors. 229 | 230 | 0.5.2 231 | ========== 232 | 233 | * Added ability to configure permissions set on each deploy (issue #32). See README for details. 234 | 235 | 0.5.1 236 | ========== 237 | 238 | * Fixed usability regression causing deploy confirmation to occur prior to display of `capistrano/magento2/pending` output when in use (issue #28) 239 | * Fixed "REVISION file doesn't exist" error when deploying for the first time when `capistrano/magento2/pending` is loaded 240 | * Fixed issue breaking initial deploy when `:magento_deploy_maintenance` is set to true 241 | 242 | 0.5.0 243 | ========== 244 | 245 | * Added ability to only deploy specific themes via the new `:magento_deploy_themes` array 246 | * Added `:magento_deploy_confim` setting which requires user confirmation of deployment to specific capistrano stages 247 | * Added call to pre-generate secure RequireJS config (issue #21) 248 | * Added workaround for Magento 2.1 specific bug where lack of a deployed_version.txt file would fail static asset deploy 249 | * Added error check on output of setup:di:compile-multi-tenant since Magento 2.0 doesn't return error codes (issue #25) 250 | * Updated formatting of pending deployment messaging 251 | * Updated composer calls to specify --no-dev and --optimize-autoloader when `:magento_deploy_production` is not set (issue #22, #23) 252 | * Fixed bug causing maintenance mode to be enabled on deploy even when `:magento_deploy_maintenance` was set to false 253 | * Fixed bug preventing the second call to `magento:setup:permissions` from being executed (issue #18) 254 | * Removed the undocumented `:deploy_warn_stages` setting from the notifier 255 | 256 | 0.4.0 257 | ========== 258 | 259 | * Added optional support for capistrano-pending gem. 260 | * Added `:magento_deploy_composer` flag. See README for details. 261 | * Added `:magento_deploy_maintenance` flag. See README for details. 262 | * Updated `:magento_deploy_languages` definition to explicitly declare default value. 263 | 264 | 0.3.0 265 | ========== 266 | 267 | * Added `:magento_deploy_production` flag to disable production deploy commands (PR #10 by @giacmir). 268 | * Added `:magento_deploy_languages` setting to support passing language list to static content generator (PR #11 by @giacmir). 269 | 270 | 0.2.4 271 | ========== 272 | 273 | * Added internal `magento:deploy:check` task and `:linked_files_touch` setting to minimize manual server setup 274 | * Moved default linked file for sitemap.xml into pub directory 275 | 276 | 0.2.3 277 | ========== 278 | 279 | * Added file check to halt deploy if app/etc/config.php is not present in repository 280 | * Added check to verify that app/etc/env.php contains an array with an install date 281 | 282 | 0.2.2 283 | ========== 284 | 285 | * Revert "Add workaround for M2.0.4 bug noted in magento/magento2#4070" 286 | 287 | 0.2.1 288 | ========== 289 | 290 | * Fixed issue with initial deploy failing before 'current' link has been created on target 291 | 292 | 0.2.0 293 | ========== 294 | 295 | * Added "smart" magento:setup:di:compile task which uses multi-tenant if available (for compatibility with 2.0 release) 296 | * Added a command_map for the bin/magento tool to simplify rake files 297 | * Added indexer:info, indexer:status, indexer:show-mode, indexer:set-mode 298 | * Added maintenance:status and maintenance:allow-ips, exposes maintenance:disable 299 | * Fixed broken error detection logic on setup:static-content:deploy 300 | * Fixed bug where magento:setup:upgrade was not using the --keep-generated flag 301 | * Fixed log bloat caused by chatty static-content:deploy 302 | * Fixed missing dependency include in deploy.rb 303 | * Fixed output of magento:cache:varnish:ban command 304 | * Fixed potential issue where if a botched release was in production, one could not roll back 305 | * Fixed technical dependency bug preventing projects from overriding the deploy.rake with a custom one 306 | * Renamed capistrano/magento2/deploy/notify to capistrano/magento2/notifier 307 | * Renamed magento:reset_permissions to magento:setup:permissions 308 | * Renamed magento:setup:static_content:deploy to magento:setup:static-content:deploy 309 | * Updated composer calls to explicitly set --prefer-dist and --no-interaction 310 | * Updated README to reflect current setup instructions 311 | 312 | 0.1.3 313 | ========== 314 | 315 | * Changed magento:cache:varnish:ban to use `:varnish_cache_hosts` array in deploy config vs hardcoding 127.0.0.1:6081 316 | 317 | 0.1.2 318 | ========== 319 | 320 | * Added information to README file regarding use of terminal-notifier functionality 321 | 322 | 0.1.1 323 | ========== 324 | 325 | * Initial functional release, tested with Magento 2.0.4 / PHP 7.0.5 326 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | ## 2 | # Copyright © 2016 by David Alger. All rights reserved 3 | # 4 | # Licensed under the Open Software License 3.0 (OSL-3.0) 5 | # See included LICENSE file for full text of OSL-3.0 6 | # 7 | # http://davidalger.com/contact/ 8 | ## 9 | 10 | source 'https://rubygems.org' 11 | gemspec 12 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Open Software License v3.0 ("OSL") 2 | 3 | This Open Software License (the "License") applies to any original work of authorship (the "Original Work") whose owner (the "Licensor") has placed the following licensing notice adjacent to the copyright notice for the Original Work: 4 | 5 | Licensed under the Open Software License version 3.0 6 | 7 | 1) Grant of Copyright License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, for the duration of the copyright, to do the following: 8 | 9 | a) to reproduce the Original Work in copies, either alone or as part of a collective work; 10 | 11 | b) to translate, adapt, alter, transform, modify, or arrange the Original Work, thereby creating derivative works ("Derivative Works") based upon the Original Work; 12 | 13 | c) to distribute or communicate copies of the Original Work and Derivative Works to the public, with the proviso that copies of Original Work or Derivative Works that You distribute or communicate shall be licensed under this Open Software License; 14 | 15 | d) to perform the Original Work publicly; and 16 | 17 | e) to display the Original Work publicly. 18 | 19 | 2) Grant of Patent License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, under patent claims owned or controlled by the Licensor that are embodied in the Original Work as furnished by the Licensor, for the duration of the patents, to make, use, sell, offer for sale, have made, and import the Original Work and Derivative Works. 20 | 21 | 3) Grant of Source Code License. The term "Source Code" means the preferred form of the Original Work for making modifications to it and all available documentation describing how to modify the Original Work. Licensor agrees to provide a machine-readable copy of the Source Code of the Original Work along with each copy of the Original Work that Licensor distributes. Licensor reserves the right to satisfy this obligation by placing a machine-readable copy of the Source Code in an information repository reasonably calculated to permit inexpensive and convenient access by You for as long as Licensor continues to distribute the Original Work. 22 | 23 | 4) Exclusions From License Grant. Neither the names of Licensor, nor the names of any contributors to the Original Work, nor any of their trademarks or service marks, may be used to endorse or promote products derived from this Original Work without express prior permission of the Licensor. Except as expressly stated herein, nothing in this License grants any license to Licensor's trademarks, copyrights, patents, trade secrets or any other intellectual property. No patent license is granted to make, use, sell, offer for sale, have made, or import embodiments of any patent claims other than the licensed claims defined in Section 2. No license is granted to the trademarks of Licensor even if such marks are included in the Original Work. Nothing in this License shall be interpreted to prohibit Licensor from licensing under terms different from this License any Original Work that Licensor otherwise would have a right to license. 24 | 25 | 5) External Deployment. The term "External Deployment" means the use, distribution, or communication of the Original Work or Derivative Works in any way such that the Original Work or Derivative Works may be used by anyone other than You, whether those works are distributed or communicated to those persons or made available as an application intended for use over a network. As an express condition for the grants of license hereunder, You must treat any External Deployment by You of the Original Work or a Derivative Work as a distribution under section 1(c). 26 | 27 | 6) Attribution Rights. You must retain, in the Source Code of any Derivative Works that You create, all copyright, patent, or trademark notices from the Source Code of the Original Work, as well as any notices of licensing and any descriptive text identified therein as an "Attribution Notice." You must cause the Source Code for any Derivative Works that You create to carry a prominent Attribution Notice reasonably calculated to inform recipients that You have modified the Original Work. 28 | 29 | 7) Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or are sublicensed to You under the terms of this License with the permission of the contributor(s) of those copyrights and patent rights. Except as expressly stated in the immediately preceding sentence, the Original Work is provided under this License on an "AS IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without limitation, the warranties of non-infringement, merchantability or fitness for a particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No license to the Original Work is granted by this License except under this disclaimer. 30 | 31 | 8) Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall the Licensor be liable to anyone for any indirect, special, incidental, or consequential damages of any character arising as a result of this License or the use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses. This limitation of liability shall not apply to the extent applicable law prohibits such limitation. 32 | 33 | 9) Acceptance and Termination. If, at any time, You expressly assented to this License, that assent indicates your clear and irrevocable acceptance of this License and all of its terms and conditions. If You distribute or communicate copies of the Original Work or a Derivative Work, You must make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of this License. This License conditions your rights to undertake the activities listed in Section 1, including your right to create Derivative Works based upon the Original Work, and doing so without honoring these terms and conditions is prohibited by copyright law and international treaty. Nothing in this License is intended to affect copyright exceptions and limitations (including "fair use" or "fair dealing"). This License shall terminate immediately and You may no longer exercise any of the rights granted to You by this License upon your failure to honor the conditions in Section 1(c). 34 | 35 | 10) Termination for Patent Action. This License shall terminate automatically and You may no longer exercise any of the rights granted to You by this License as of the date You commence an action, including a cross-claim or counterclaim, against Licensor or any licensee alleging that the Original Work infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of the Original Work with other software or hardware. 36 | 37 | 11) Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the Original Work outside the scope of this License or after its termination shall be subject to the requirements and penalties of copyright or patent law in the appropriate jurisdiction. This section shall survive the termination of this License. 38 | 39 | 12) Attorneys' Fees. In any action to enforce the terms of this License or seeking damages relating thereto, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. This section shall survive the termination of this License. 40 | 41 | 13) Miscellaneous. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. 42 | 43 | 14) Definition of "You" in This License. "You" throughout this License, whether in upper or lower case, means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with you. For purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. 44 | 45 | 15) Right to Use. You may use the Original Work in all ways not otherwise restricted or conditioned by this License or by law, and Licensor promises not to interfere with or be responsible for such uses by You. 46 | 47 | 16) Modification of This License. This License is Copyright © 2005 Lawrence Rosen. Permission is granted to copy, distribute, or communicate this License without modification. Nothing in this License permits You to modify this License as applied to the Original Work or to Derivative Works. However, You may modify the text of this License and copy, distribute or communicate your modified version (the "Modified License") and apply it to other original works of authorship subject to the following conditions: (i) You may not indicate in any way that your Modified License is the "Open Software License" or "OSL" and you may not use those names in the name of your Modified License; (ii) You must replace the notice specified in the first paragraph above with the notice "Licensed under " or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Capistrano::Magento2 2 | 3 | [![Gem Version](https://badge.fury.io/rb/capistrano-magento2.svg)](https://badge.fury.io/rb/capistrano-magento2) 4 | 5 | A Capistrano extension for Magento 2 deployments. Takes care of specific Magento 2 requirements and adds tasks specific to the Magento 2 application. Supports zero-down deployments based on differences in deployed `config.php` and db status as reported by Magento's `setup:db:status` CLI command. When themes and scopes have been dumped to `config.php` via `bin/magento app:config:dump scopes themes i18n` then zero-side-effect pipeline will be utilized such that no database nor cache backend configuration are available during the build process. 6 | 7 | ## Supported Magento Versions 8 | 9 | The following describes minimum Magento versions supported by releases of this gem. Please use an earlier version to deploy older releases of Magento not supported by the most recent iterations of this gem. 10 | 11 | * Version 0.9.x supports deployment of Magento 2.3.0 and later. 12 | * Version 0.7.x supports deployment of Magento 2.1.1 and later. 13 | 14 | ## Installation 15 | 16 | ### Standalone Installation 17 | 18 | $ gem install capistrano-magento2 19 | 20 | ### Using Bundler 21 | 22 | 1. Add the following to your project's `Gemfile`: 23 | 24 | ```ruby 25 | source 'https://rubygems.org' 26 | gem 'capistrano-magento2' 27 | ``` 28 | 29 | 2. Execute the following: 30 | 31 | $ bundle install 32 | 33 | ## Usage 34 | 35 | 1. Install Capistrano in your Magento project: 36 | 37 | ```shell 38 | $ cd 39 | $ mkdir -p tools/cap 40 | $ cd ./tools/cap 41 | $ cap install 42 | ``` 43 | _Note: By default, Capistrano creates "staging" and "production" stages. If you want to define custom staging areas, you can do so using the "STAGES" option (e.g. `cap install STAGES=stage,prod`). Built-in notifications ([see below](#terminal-notifier-on-os-x)) confirm deploy action on both "production" and "prod" area names by default._ 44 | 45 | 2. Update your project's `Capfile` to look like the following: 46 | 47 | ```ruby 48 | # Load DSL and set up stages 49 | require 'capistrano/setup' 50 | 51 | # Load Magento deployment tasks 52 | require 'capistrano/magento2/deploy' 53 | require 'capistrano/magento2/pending' 54 | 55 | # Load Git plugin 56 | require "capistrano/scm/git" 57 | install_plugin Capistrano::SCM::Git 58 | 59 | # Load custom tasks from `lib/capistrano/tasks` if you have any defined 60 | Dir.glob('lib/capistrano/tasks/*.rake').each { |r| import r } 61 | ``` 62 | 63 | 3. Configure Capistrano, per the [Capistrano Configuration](#capistrano-configuration) section below. 64 | 65 | 4. Configure your server(s), per the [Server Configuration](#server-configuration) section below. 66 | 67 | 5. Deploy Magento 2 to staging or production by running the following command in the `tools/cap` directory: 68 | 69 | ```shell 70 | $ cap staging deploy 71 | ``` 72 | or 73 | ```shell 74 | $ cap production deploy 75 | ``` 76 | 77 | ## Default Configuration 78 | 79 | ### Capistrano Configuration 80 | 81 | Before you can use Capistrano to deploy, you must configure the `config/deploy.rb` and `config/deploy/*.rb` files. This section will cover the basic details for configuring these files. Refer to the [Capistrano documentation](http://capistranorb.com/documentation/getting-started/preparing-your-application/#configure-your-server-addresses-in-the-generated-files) and [README](https://github.com/capistrano/capistrano/blob/master/README.md) for more details. 82 | 83 | 1. Configuring `config/deploy.rb` 84 | 85 | Update the `:application` and `:repo_url` values in `config/deploy.rb`: 86 | 87 | ```ruby 88 | # Something unique such as the website or company name 89 | set :application, 'example' 90 | # The repository that hosts the Magento 2 application (Magento should live in the root of the repo) 91 | set :repo_url, 'git@github.com:acme/example-com.git' 92 | ``` 93 | 94 | 2. Configuring `config/deploy/*.rb` files 95 | 96 | Capistrano allows you to use server-based or role-based syntax. You can read through the comments in the file to learn more about each option. If you have a single application server then the server-based syntax is the simplest configuration option. 97 | 98 | * Single application server 99 | 100 | If your stage and production environments consist of a single application server, your configuration files should look something like this: 101 | 102 | `config/deploy/production.rb` 103 | ```ruby 104 | server 'www.example.com', user: 'www-data', roles: %w{app db web} 105 | 106 | set :deploy_to, '/var/www/html' 107 | set :branch, proc { `git rev-parse --abbrev-ref master`.chomp } 108 | ``` 109 | 110 | `config/deploy/staging.rb` 111 | ```ruby 112 | server 'stage.example.com', user: 'www-data', roles: %w{app db web} 113 | 114 | set :deploy_to, '/var/www/html' 115 | set :branch, proc { `git rev-parse --abbrev-ref develop`.chomp } 116 | ``` 117 | 118 | * Multiple application servers 119 | 120 | Refer to the "role-based syntax" comments in the `config/deploy/*.rb` files or to the [Capistrano documentation](http://capistranorb.com/documentation/getting-started/preparing-your-application/#configure-your-server-addresses-in-the-generated-files) for details on how to configure multiple application servers. 121 | 122 | ### Magento Deploy Settings 123 | 124 | | setting | default | what it does 125 | | ------------------------------ | -------- | --- 126 | | `:magento_deploy_setup_role` | `:all` | Role from which primary host is chosen to run things like setup:upgrade on 127 | | `:magento_deploy_cache_shared` | `true` | If true, cache operations are restricted to the primary node in setup role 128 | | `:magento_deploy_languages` | `[]` | Array of languages passed to static content deploy routine 129 | | `:magento_deploy_themes` | `[]` | Array of themes passed to static content deploy 130 | | `:magento_deploy_jobs` | `nil` | Number of threads to use for static content deploy 131 | | `:magento_deploy_composer` | `true` | Enables composer install behavior in the built-in deploy routine 132 | | `:magento_deploy_production` | `true` | Enables production specific DI compilation and static content generation 133 | | `:magento_deploy_no_dev` | `true` | Enables use of --no-dev flag on composer install 134 | | `:magento_deploy_maintenance` | `true` | Enables use of maintenance mode while magento:setup:upgrade runs 135 | | `:magento_deploy_confirm` | `[]` | Used to require confirmation of deployment to a set of capistrano stages 136 | | `:magento_deploy_chmod_d` | `'2770'` | Default permissions applied to all directories in the release path 137 | | `:magento_deploy_chmod_f` | `'0660'` | Default permissions applied to all non-executable files in the release path 138 | | `:magento_deploy_chmod_x` | `['bin/magento']` | Default list of files in release path to set executable bit on 139 | | `:magento_deploy_chcon_dirs` | `['var']` | Default list of directories on which to recursively set an SELinux context type 140 | | `:magento_deploy_chcon_type` | `httpd_sys_rw_content_t` | Default SELinux context type to set on directories which should be writeable by application 141 | | `:magento_deploy_strategy` | `nil` | Can be `quick`, `standard` or `compact` 142 | 143 | #### Example Usage 144 | 145 | Add a line similar to the following in `config/deploy.rb` to set a custom value on one of the above settings: 146 | 147 | ```ruby 148 | set :magento_deploy_jobs, '$(nproc)' 149 | set :magento_deploy_themes, ['Magento/backend', 'Magento/blank'] 150 | set :magento_deploy_languages, ['en_US', 'en_CA'] 151 | ``` 152 | 153 | ### Capistrano Built-Ins 154 | 155 | For the sake of simplicity in new project setups `:linked_dirs` and `:linked_files` are pre-configured per the following. 156 | 157 | ```ruby 158 | set :linked_files, [ 159 | 'app/etc/env.php', 160 | 'var/.setup_cronjob_status', 161 | 'var/.update_cronjob_status' 162 | ] 163 | 164 | set :linked_dirs, [ 165 | 'pub/media', 166 | 'pub/sitemaps', 167 | 'var/backups', 168 | 'var/composer_home', 169 | 'var/importexport', 170 | 'var/import_history', 171 | 'var/log', 172 | 'var/session', 173 | 'var/tmp' 174 | ] 175 | ``` 176 | 177 | If you would like to customize the linked files or directories for your project, you can copy either one or both of the above arrays into the `config/deploy.rb` or `config/deploy/*.rb` files and tweak them to fit your project's needs. Alternatively, you can add a single linked dir (or file) using `append` like this: 178 | 179 | ```ruby 180 | append :linked_dirs, 'path/to/link' 181 | ``` 182 | 183 | ### Composer Auth Credentials 184 | 185 | Magento 2's composer repository requires auth credentials to install. These can be set on target servers in a global composer `auth.json` file, the project's `composer.json` or by setting them in your deployment configuration using the following two settings: 186 | 187 | ```ruby 188 | set :magento_auth_public_key, '' 189 | set :magento_auth_private_key, '' 190 | ``` 191 | 192 | To obtain these credentials, reference the official documentation on DevDocs: [Get your authentication keys](http://devdocs.magento.com/guides/v2.0/install-gde/prereq/connect-auth.html) 193 | 194 | **Caution:** When using these settings, the values will be logged to the `log/capistrano.log` file by SSHKit. They will not, however, be included in the general command output by default. 195 | 196 | ### Magento 2 Deploy Routine 197 | 198 | A pre-built deploy routine is available out-of-the-box. This can be overriden on a per-project basis by including only the Magento 2 specific tasks and defining your own `deploy.rake` file under `lib/capistrano/tasks` in your projects Capistrano install location. 199 | 200 | To see what process the built-in routine runs, take a look at the included rake file here: https://github.com/davidalger/capistrano-magento2/blob/master/lib/capistrano/tasks/deploy.rake 201 | 202 | ## Server Configuration 203 | 204 | ### Web Server Root Path 205 | 206 | Before deploying with Capistrano, you must update each of your web servers to point to the `current` directory inside of the configured `:deploy_to` directory. For example: `/var/www/html/current/pub` Refer to the [Capistrano Structure](http://capistranorb.com/documentation/getting-started/structure/) to learn more about Capistrano's folder structure. 207 | 208 | ### PHP Opcache Reset 209 | 210 | When doing atomic deployments with php-opcache installed on a server, the cache will reach a full state after which application performance will degrade as a result of the opcache not being able to do it's job. To work nicely with this, there is support included for automatically resetting the php-opcache after a release is published. 211 | 212 | To use this, include `require 'capistrano/magento2/cachetool'` in your `Capfile` and make sure there is an `/etc/cachetool.yml` or `/var/www/html/.cachetool.yml` (assuming `:deploy_to` points at `/var/www/html`) file configured with contents like the following: 213 | 214 | adapter: fastcgi 215 | fastcgi: /var/run/php-fpm/www-data.sock 216 | temp_dir: /dev/shm/cachetool 217 | extensions: [ opcache ] 218 | 219 | With this configuration in place, be sure cachetool ([available from here](http://gordalina.github.io/cachetool/)) has already been installed on the server and is available in `$PATH`. 220 | 221 | Congratulations! You should now begin to see the pre-deployemnt opcache status information when running a deployment followed immediately be the `cachetool opcache:reset` command used to keep things humming nicely along. 222 | 223 | ## Magento Specific Tasks 224 | 225 | All Magento 2 tasks used by the built-in `deploy.rake` file as well as some additional commands are implemented and exposed to the end-user for use directly via the cap tool. You can also see this list by running `cap -T` from your shell. 226 | 227 | | cap command | what it does | 228 | | ------------------------------------- | -------------------------------------------------- | 229 | | magento:cache:clean | Clean Magento cache by types | 230 | | magento:cache:disable | Disable Magento cache | 231 | | magento:cache:enable | Enable Magento cache | 232 | | magento:cache:flush | Flush Magento cache storage | 233 | | magento:cache:status | Check Magento cache enabled status | 234 | | magento:cache:varnish:ban | Add ban to Varnish for url(s) | 235 | | magento:composer:install | Run composer install | 236 | | magento:deploy:mode:production | Enables production mode | 237 | | magento:deploy:mode:show | Displays current application mode | 238 | | magento:indexer:info | Shows allowed indexers | 239 | | magento:indexer:reindex | Reindex data by all indexers | 240 | | magento:indexer:set-mode[mode,index] | Sets mode of all indexers | 241 | | magento:indexer:show-mode[index] | Shows mode of all indexers | 242 | | magento:indexer:status | Shows status of all indexers | 243 | | magento:maintenance:allow-ips[ip] | Sets maintenance mode exempt IPs | 244 | | magento:maintenance:disable | Disable maintenance mode | 245 | | magento:maintenance:enable | Enable maintenance mode | 246 | | magento:maintenance:status | Displays maintenance mode status | 247 | | magento:setup:di:compile | Runs dependency injection compilation routine | 248 | | magento:setup:permissions | Sets proper permissions on application | 249 | | magento:setup:static-content:deploy | Deploys static view files | 250 | | magento:setup:upgrade | Run the Magento upgrade process | 251 | 252 | ## Pending Changes Support 253 | 254 | When the line `require 'capistrano/magento2/pending'` is included in your `Capfile` per the recommended configuration above, this gem will report changes pending deployment in an abbreviated git log style format. Here is an example: 255 | 256 | ``` 257 | 00:00 deploy:pending:log 258 | 01 git fetch origin 259 | ✔ 01 dalger@localhost 1.241s 260 | ✔ 01 dalger@localhost 1.259s 261 | Changes pending deployment on web1 (tags/2.1.2 -> 2.1): 262 | f511288 Thu Feb 23 12:19:20 2017 -0600 David Alger (HEAD -> 2.1, tag: 2.1.4, origin/2.1) Magento 2.1.4 263 | 7fb219c Thu Feb 23 12:17:11 2017 -0600 David Alger (tag: 2.1.3) Magento 2.1.3 264 | 570c9b3 Thu Feb 23 12:12:43 2017 -0600 David Alger Updated capistrano configuration 265 | No changes to deploy on web2 (from and to are the same: 2.1 -> 2.1) 266 | ``` 267 | 268 | When there are no changes due for deployment to any host, a warning requiring confirmation will be emitted by default: 269 | 270 | ``` 271 | No changes to deploy on web1 (from and to are the same: 2.1 -> 2.1) 272 | No changes to deploy on web2 (from and to are the same: 2.1 -> 2.1) 273 | Are you sure you want to continue? [y/n] 274 | ``` 275 | 276 | This confirmational warning can be disabled by including the following in your project's configuration: 277 | 278 | ```ruby 279 | set :magento_deploy_pending_warn, false 280 | ``` 281 | 282 | ### Pending Changes Configuration 283 | 284 | | setting | what it does 285 | | -------------------------------- | ---------- 286 | | `:magento_deploy_pending_role` | Role to check for pending changes on; defaults to `:all` 287 | | `:magento_deploy_pending_warn` | Set this to `false` to disable confirmational warning on zero-change deployments 288 | | `:magento_deploy_pending_format` | Can be used to set a custom change log format; refer to `defaults.rb` for example 289 | 290 | ### Pending Changes Tasks 291 | 292 | | cap command | what it does | 293 | | ------------------------------------- | -------------------------------------------------- | 294 | | deploy:pending | Displays a summary of commits pending deployment | 295 | 296 | Note: For more details including screenshots of what this functionality does, reference [this post](https://github.com/davidalger/capistrano-magento2/issues/58#issuecomment-282404477). 297 | 298 | ## Terminal Notifier on OS X 299 | 300 | This gem includes an optional configuration file include which adds notification support via the [terminal-notifier](https://rubygems.org/gems/terminal-notifier) gem. To configure notifications, simply add the following line to your `Capfile`: 301 | 302 | ```ruby 303 | require 'capistrano/magento2/notifier' 304 | ``` 305 | 306 | **Notice:** The `terminal-notifier` gem is currently macOS specific and thus can not be used on generic *nix environments. Because this gem has been known to cause ruby stability issues on certain non-macOS environments, it is not specified as a hard requirement in this gem's gemspec. When using this functionality, it is expected the gem either be already present on your working environment or be added to your project's `Gemfile`: 307 | 308 | ```ruby 309 | gem 'terminal-notifier' 310 | ``` 311 | 312 | ## Development 313 | 314 | After checking out the repo, run `bundle install` to install dependencies. Make the necessary changes, then run `bundle exec rake install` to install a modified version of the gem on your local system. 315 | 316 | To release a new version, update the version number in `capistrano/magento2/version.rb`, merge all changes to master, and then run `bundle exec rake release`. This will create a git tag for the version (the tag will apply to the current HEAD), push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org). 317 | 318 | _Note: Releasing a new version of the gem is only possible for those with maintainer access to the gem on rubygems.org._ 319 | 320 | ## Contributing 321 | 322 | Bug reports and pull requests are welcome on GitHub at https://github.com/davidalger/capistrano-magento2. 323 | 324 | ## License 325 | 326 | This project is licensed under the Open Software License 3.0 (OSL-3.0). See included LICENSE file for full text of OSL-3.0. 327 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | ## 2 | # Copyright © 2016 by David Alger. All rights reserved 3 | # 4 | # Licensed under the Open Software License 3.0 (OSL-3.0) 5 | # See included LICENSE file for full text of OSL-3.0 6 | # 7 | # http://davidalger.com/contact/ 8 | ## 9 | 10 | require 'bundler/gem_tasks' 11 | 12 | task default: %w[test] 13 | 14 | task :test do 15 | puts "TODO: Create real integration tests!" 16 | end 17 | -------------------------------------------------------------------------------- /capistrano-magento2.gemspec: -------------------------------------------------------------------------------- 1 | ## 2 | # Copyright © 2016 by David Alger. All rights reserved 3 | # 4 | # Licensed under the Open Software License 3.0 (OSL-3.0) 5 | # See included LICENSE file for full text of OSL-3.0 6 | # 7 | # http://davidalger.com/contact/ 8 | ## 9 | 10 | lib = File.expand_path('../lib', __FILE__) 11 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 12 | require 'capistrano/magento2/version' 13 | 14 | Gem::Specification.new do |spec| 15 | spec.name = 'capistrano-magento2' 16 | spec.version = Capistrano::Magento2::VERSION 17 | spec.authors = ['David Alger'] 18 | spec.email = ['davidmalger@gmail.com'] 19 | 20 | spec.summary = %q{A Capistrano extension for Magento 2 deployments.} 21 | spec.description = %Q{#{spec.summary} Takes care of specific Magento 2 requirements and adds tasks specific to the Magento 2 application.} 22 | spec.homepage = 'https://github.com/davidalger/capistrano-magento2' 23 | spec.license = 'OSL-3.0' 24 | 25 | spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) } 26 | spec.bindir = 'bin' 27 | spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } 28 | spec.require_paths = ['lib'] 29 | 30 | spec.add_dependency 'capistrano', '~> 3.14' 31 | 32 | spec.add_development_dependency 'bundler', '~> 2.1' 33 | spec.add_development_dependency 'rake', '~> 13.0' 34 | end 35 | -------------------------------------------------------------------------------- /lib/capistrano-magento2.rb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidalger/capistrano-magento2/3d32c7d654bd9221f67e20c27fc4e62503bdd73d/lib/capistrano-magento2.rb -------------------------------------------------------------------------------- /lib/capistrano/magento2.rb: -------------------------------------------------------------------------------- 1 | ## 2 | # Copyright © 2016 by David Alger. All rights reserved 3 | # 4 | # Licensed under the Open Software License 3.0 (OSL-3.0) 5 | # See included LICENSE file for full text of OSL-3.0 6 | # 7 | # http://davidalger.com/contact/ 8 | ## 9 | 10 | require 'date' 11 | 12 | SSHKit.config.command_map[:magento] = "/usr/bin/env php -f bin/magento --" 13 | 14 | module Capistrano 15 | module Magento2 16 | module Helpers 17 | def disabled_modules 18 | output = capture :magento, 'module:status --no-ansi' 19 | output = output.split("disabled modules:\n", 2)[1] 20 | 21 | if output == nil or output.strip == "None" 22 | return [] 23 | end 24 | return output.split("\n") 25 | end 26 | 27 | def cache_hosts 28 | return fetch(:magento_deploy_cache_shared) ? (primary fetch :magento_deploy_setup_role) : (release_roles :all) 29 | end 30 | end 31 | 32 | module Setup 33 | def deployed_version 34 | # Generate a static content version string, but only if one has not already been set on a previous call 35 | if not fetch(:magento_static_deployed_version) 36 | set :magento_static_deployed_version, DateTime.now.strftime("%s") 37 | info "Static content version: #{fetch(:magento_static_deployed_version)}" 38 | end 39 | return fetch(:magento_static_deployed_version) 40 | end 41 | end 42 | end 43 | end 44 | 45 | load File.expand_path('../tasks/magento.rake', __FILE__) 46 | 47 | namespace :load do 48 | task :defaults do 49 | load 'capistrano/magento2/defaults.rb' 50 | end 51 | end 52 | -------------------------------------------------------------------------------- /lib/capistrano/magento2/cachetool.rb: -------------------------------------------------------------------------------- 1 | ## 2 | # Copyright © 2018 by David Alger. All rights reserved 3 | # 4 | # Licensed under the Open Software License 3.0 (OSL-3.0) 5 | # See included LICENSE file for full text of OSL-3.0 6 | # 7 | # http://davidalger.com/contact/ 8 | ## 9 | 10 | require 'capistrano/deploy' 11 | 12 | SSHKit.config.command_map[:cachetool] = "/usr/bin/env cachetool --" 13 | 14 | load File.expand_path('../../tasks/cachetool.rake', __FILE__) 15 | -------------------------------------------------------------------------------- /lib/capistrano/magento2/defaults.rb: -------------------------------------------------------------------------------- 1 | ## 2 | # Copyright © 2016 by David Alger. All rights reserved 3 | # 4 | # Licensed under the Open Software License 3.0 (OSL-3.0) 5 | # See included LICENSE file for full text of OSL-3.0 6 | # 7 | # http://davidalger.com/contact/ 8 | ## 9 | 10 | set :linked_files, fetch(:linked_files, []).push( 11 | 'app/etc/env.php', 12 | 'var/.setup_cronjob_status', 13 | 'var/.update_cronjob_status' 14 | ) 15 | 16 | set :linked_files_touch, fetch(:linked_files_touch, []).push( 17 | 'app/etc/env.php', 18 | 'var/.setup_cronjob_status', 19 | 'var/.update_cronjob_status' 20 | ) 21 | 22 | set :linked_dirs, fetch(:linked_dirs, []).push( 23 | 'pub/media', 24 | 'pub/sitemaps', 25 | 'var/backups', 26 | 'var/composer_home', 27 | 'var/importexport', 28 | 'var/import_history', 29 | 'var/export', 30 | 'var/log', 31 | 'var/session', 32 | 'var/tmp' 33 | ) 34 | 35 | # magento composer repository auth credentials 36 | set :magento_auth_repo_name, fetch(:magento_auth_repo_name, 'http-basic.repo.magento.com') 37 | set :magento_auth_public_key, fetch(:magento_auth_public_key, false) 38 | set :magento_auth_private_key, fetch(:magento_auth_private_key, false) 39 | 40 | # deploy permissions defaults 41 | set :magento_deploy_chmod_d, fetch(:magento_deploy_chmod_d, '2770') 42 | set :magento_deploy_chmod_f, fetch(:magento_deploy_chmod_f, '0660') 43 | set :magento_deploy_chmod_x, fetch(:magento_deploy_chmod_x, ['bin/magento']) 44 | 45 | # deploy selinux defaults 46 | set :magento_deploy_chcon_dirs, fetch(:magento_deploy_chcon_dirs, ['var']) 47 | set :magento_deploy_chcon_type, fetch(:magento_deploy_chcon_type, 'httpd_sys_rw_content_t') 48 | 49 | # deploy configuration defaults 50 | set :magento_deploy_composer, fetch(:magento_deploy_composer, true) 51 | set :magento_deploy_confirm, fetch(:magento_deploy_confirm, []) 52 | set :magento_deploy_languages, fetch(:magento_deploy_languages, []) 53 | set :magento_deploy_maintenance, fetch(:magento_deploy_maintenance, true) 54 | set :magento_deploy_production, fetch(:magento_deploy_production, true) 55 | set :magento_deploy_no_dev, fetch(:magento_deploy_no_dev, true) 56 | set :magento_deploy_themes, fetch(:magento_deploy_themes, []) 57 | set :magento_deploy_jobs, fetch(:magento_deploy_jobs, nil) 58 | set :magento_deploy_strategy, fetch(:magento_deploy_strategy, nil) 59 | 60 | # deploy targetting defaults 61 | set :magento_deploy_setup_role, fetch(:magento_deploy_setup_role, :all) 62 | set :magento_deploy_cache_shared, fetch(:magento_deploy_cache_shared, true) 63 | 64 | # pending deploy check defaults 65 | set :magento_deploy_pending_role, fetch(:magento_deploy_pending_role, :all) 66 | set :magento_deploy_pending_warn, fetch(:magento_deploy_pending_warn, true) 67 | set :magento_deploy_pending_format, fetch( 68 | :magento_deploy_pending_format, 69 | '--pretty="format:%C(yellow)%h %Cblue%>(12)%ai %Cgreen%<(7)%aN%Cred%d %Creset%s"' 70 | ) 71 | 72 | # internal flags 73 | set :magento_internal_zero_down_flag, fetch(:magento_internal_zero_down_flag, false) 74 | -------------------------------------------------------------------------------- /lib/capistrano/magento2/deploy.rb: -------------------------------------------------------------------------------- 1 | ## 2 | # Copyright © 2016 by David Alger. All rights reserved 3 | # 4 | # Licensed under the Open Software License 3.0 (OSL-3.0) 5 | # See included LICENSE file for full text of OSL-3.0 6 | # 7 | # http://davidalger.com/contact/ 8 | ## 9 | 10 | require 'capistrano/deploy' 11 | require 'capistrano/magento2' 12 | 13 | load File.expand_path('../../tasks/deploy.rake', __FILE__) 14 | -------------------------------------------------------------------------------- /lib/capistrano/magento2/notifier.rb: -------------------------------------------------------------------------------- 1 | ## 2 | # Copyright © 2016 by David Alger. All rights reserved 3 | # 4 | # Licensed under the Open Software License 3.0 (OSL-3.0) 5 | # See included LICENSE file for full text of OSL-3.0 6 | # 7 | # http://davidalger.com/contact/ 8 | ## 9 | 10 | require 'capistrano/deploy' 11 | 12 | load File.expand_path('../../tasks/notifier.rake', __FILE__) 13 | -------------------------------------------------------------------------------- /lib/capistrano/magento2/pending.rb: -------------------------------------------------------------------------------- 1 | ## 2 | # Copyright © 2016 by David Alger. All rights reserved 3 | # 4 | # Licensed under the Open Software License 3.0 (OSL-3.0) 5 | # See included LICENSE file for full text of OSL-3.0 6 | # 7 | # http://davidalger.com/contact/ 8 | ## 9 | 10 | require 'capistrano/deploy' 11 | require 'capistrano/magento2' 12 | 13 | module Capistrano 14 | module Magento2 15 | module Pending 16 | def ensure_revision inform_user = false 17 | if test "[ -f #{current_path}/REVISION ]" 18 | yield 19 | else 20 | warn "\e[0;31mSkipping pending changes check on #{host} (no REVISION file found)\e[0m" if inform_user 21 | return false 22 | end 23 | return true 24 | end 25 | 26 | def from_rev 27 | within current_path do 28 | current_revision = capture(:cat, "REVISION") 29 | 30 | run_locally do 31 | return capture(:git, "name-rev --always --name-only #{current_revision}") # find symbolic name for ref 32 | end 33 | end 34 | end 35 | 36 | def to_rev 37 | run_locally do 38 | to = fetch(:branch) 39 | 40 | # get target branch upstream if there is one 41 | if test(:git, "rev-parse --abbrev-ref --symbolic-full-name #{to}@{u}") 42 | to = capture(:git, "rev-parse --abbrev-ref --symbolic-full-name #{to}@{u}") 43 | end 44 | 45 | # find symbolic name for revision 46 | to = capture(:git, "name-rev --always --name-only #{to}") 47 | end 48 | end 49 | end 50 | end 51 | end 52 | 53 | load File.expand_path('../../tasks/pending.rake', __FILE__) 54 | -------------------------------------------------------------------------------- /lib/capistrano/magento2/version.rb: -------------------------------------------------------------------------------- 1 | ## 2 | # Copyright © 2016 by David Alger. All rights reserved 3 | # 4 | # Licensed under the Open Software License 3.0 (OSL-3.0) 5 | # See included LICENSE file for full text of OSL-3.0 6 | # 7 | # http://davidalger.com/contact/ 8 | ## 9 | 10 | module Capistrano 11 | module Magento2 12 | VERSION = '0.9.4' 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /lib/capistrano/tasks/cachetool.rake: -------------------------------------------------------------------------------- 1 | ## 2 | # Copyright © 2018 by David Alger. All rights reserved 3 | # 4 | # Licensed under the Open Software License 3.0 (OSL-3.0) 5 | # See included LICENSE file for full text of OSL-3.0 6 | # 7 | # http://davidalger.com/contact/ 8 | ## 9 | 10 | after "deploy:published", "cachetool:opcache:status" 11 | after "deploy:published", "cachetool:opcache:reset" 12 | 13 | namespace :cachetool do 14 | namespace :opcache do 15 | desc "Resets the contents of the php-opcode cache" 16 | task :reset do 17 | on release_roles :all do 18 | within release_path do 19 | execute :cachetool, 'opcache:reset' 20 | end 21 | end 22 | end 23 | 24 | desc "Show information about the php-opcode cache" 25 | task :status do 26 | # Due to nature of the output, run this in sequence vs in parallel (the default) with shortest possible wait time 27 | on release_roles(:all), in: :sequence, wait: 1 do 28 | within release_path do 29 | execute :cachetool, 'opcache:status' 30 | end 31 | end 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /lib/capistrano/tasks/deploy.rake: -------------------------------------------------------------------------------- 1 | ## 2 | # Copyright © 2016 by David Alger. All rights reserved 3 | # 4 | # Licensed under the Open Software License 3.0 (OSL-3.0) 5 | # See included LICENSE file for full text of OSL-3.0 6 | # 7 | # http://davidalger.com/contact/ 8 | ## 9 | 10 | include Capistrano::Magento2::Helpers 11 | 12 | namespace :deploy do 13 | before 'deploy:check:linked_files', 'magento:deploy:check' 14 | 15 | # If both 'scopes' and 'themes' are available in app/etc/config.php then the build should not require database or 16 | # cache backend configuration to deploy. Removing the link to app/etc/env.php in this case prevents any possible 17 | # side effects that may arise from the build running in parallel to the live production release (such as the cache 18 | # being randomly disabled during the composer install step of the build, something which has been observed). This 19 | # requires "bin/magento app:config:dump scopes themes i18n" be run to dump theme/store config and the result comitted to repository 20 | before 'deploy:symlink:linked_files', :detect_scd_config do 21 | on primary fetch(:magento_deploy_setup_role) do 22 | unless test %Q[#{SSHKit.config.command_map[:php]} -r ' 23 | $cfg = include "#{release_path}/app/etc/config.php"; 24 | exit((int)(isset($cfg["scopes"]) && isset($cfg["themes"]))); 25 | '] 26 | info "Removing app/etc/env.php from :linked_dirs for zero-side-effect pipeline deployment." 27 | remove :linked_files, 'app/etc/env.php' 28 | end 29 | end 30 | end 31 | 32 | before :starting, :confirm_action do 33 | if fetch(:magento_deploy_confirm).include? fetch(:stage).to_s 34 | print "\e[0;31m Are you sure you want to deploy to #{fetch(:stage).to_s}? [y/n] \e[0m" 35 | proceed = STDIN.gets[0..0] rescue nil 36 | exit unless proceed == 'y' || proceed == 'Y' 37 | end 38 | end 39 | 40 | # Links app/etc/env.php if previously dropped from :linked_dirs in :detect_scd_config 41 | task 'symlink:link_env_php' do 42 | on release_roles :all do 43 | # Normally this would be wrapped in a conditional, but during SCD and/or DI compile Magento frequently writes 44 | # to cache_types -> compiled_config resulting in an env.php file being present (albeit the wrong one) 45 | execute :ln, "-fsn #{shared_path}/app/etc/env.php #{release_path}/app/etc/env.php" 46 | end 47 | end 48 | 49 | task :updated do 50 | invoke 'magento:deploy:verify' 51 | invoke 'magento:composer:install' if fetch(:magento_deploy_composer) 52 | invoke 'magento:setup:permissions' 53 | invoke 'magento:setup:selinux' 54 | 55 | if fetch(:magento_deploy_production) 56 | invoke 'magento:setup:static-content:deploy' 57 | invoke 'magento:setup:di:compile' 58 | invoke 'magento:composer:dump-autoload' if fetch(:magento_deploy_composer) 59 | end 60 | 61 | invoke 'deploy:symlink:link_env_php' 62 | 63 | if fetch(:magento_deploy_production) 64 | invoke 'magento:deploy:mode:production' 65 | end 66 | 67 | invoke! 'magento:setup:permissions' 68 | invoke 'magento:maintenance:check' 69 | invoke 'magento:maintenance:enable' if fetch(:magento_deploy_maintenance) 70 | 71 | on release_roles :all do 72 | if test "[ -f #{current_path}/bin/magento ]" 73 | within current_path do 74 | execute :magento, 'maintenance:enable' if fetch(:magento_deploy_maintenance) 75 | end 76 | end 77 | end 78 | 79 | if not fetch(:magento_internal_zero_down_flag) 80 | on cache_hosts do 81 | within release_path do 82 | execute :magento, 'cache:flush' 83 | end 84 | end 85 | invoke 'magento:app:config:import' 86 | invoke 'magento:setup:db:schema:upgrade' 87 | invoke 'magento:setup:db:data:upgrade' 88 | end 89 | 90 | on primary fetch(:magento_deploy_setup_role) do 91 | within release_path do 92 | _disabled_modules = disabled_modules 93 | if _disabled_modules.count > 0 94 | info "\nThe following modules are disabled per app/etc/config.php:\n" 95 | _disabled_modules.each do |module_name| 96 | info '- ' + module_name 97 | end 98 | end 99 | end 100 | end 101 | end 102 | 103 | task :published do 104 | invoke 'magento:cache:flush' 105 | invoke 'magento:cache:varnish:ban' 106 | invoke 'magento:maintenance:disable' if fetch(:magento_deploy_maintenance) 107 | end 108 | end 109 | -------------------------------------------------------------------------------- /lib/capistrano/tasks/magento.rake: -------------------------------------------------------------------------------- 1 | ## 2 | # Copyright © 2016 by David Alger. All rights reserved 3 | # 4 | # Licensed under the Open Software License 3.0 (OSL-3.0) 5 | # See included LICENSE file for full text of OSL-3.0 6 | # 7 | # http://davidalger.com/contact/ 8 | ## 9 | 10 | include Capistrano::Magento2::Helpers 11 | include Capistrano::Magento2::Setup 12 | 13 | namespace :magento do 14 | 15 | namespace :app do 16 | namespace :config do 17 | desc 'Create dump of application config' 18 | task :dump do 19 | on primary fetch(:magento_deploy_setup_role) do 20 | within release_path do 21 | execute :magento, 'app:config:dump' 22 | end 23 | end 24 | end 25 | 26 | desc 'Import data from shared config files' 27 | task :import do 28 | on primary fetch(:magento_deploy_setup_role) do 29 | within release_path do 30 | execute :magento, 'app:config:import --no-interaction' 31 | end 32 | end 33 | end 34 | 35 | desc 'Checks if config propagation requires update' 36 | task :status do 37 | on primary fetch(:magento_deploy_setup_role) do 38 | within release_path do 39 | execute :magento, 'app:config:status' 40 | end 41 | end 42 | end 43 | end 44 | end 45 | 46 | namespace :cache do 47 | desc 'Flush Magento cache storage' 48 | task :flush do 49 | on cache_hosts do 50 | within release_path do 51 | execute :magento, 'cache:flush' 52 | end 53 | end 54 | end 55 | 56 | desc 'Clean Magento cache by types' 57 | task :clean do 58 | on cache_hosts do 59 | within release_path do 60 | execute :magento, 'cache:clean' 61 | end 62 | end 63 | end 64 | 65 | desc 'Enable Magento cache' 66 | task :enable do 67 | on cache_hosts do 68 | within release_path do 69 | execute :magento, 'cache:enable' 70 | end 71 | end 72 | end 73 | 74 | desc 'Disable Magento cache' 75 | task :disable do 76 | on cache_hosts do 77 | within release_path do 78 | execute :magento, 'cache:disable' 79 | end 80 | end 81 | end 82 | 83 | desc 'Check Magento cache enabled status' 84 | task :status do 85 | on cache_hosts do 86 | within release_path do 87 | execute :magento, 'cache:status' 88 | end 89 | end 90 | end 91 | 92 | namespace :varnish do 93 | # TODO: Document what the magento:cache:varnish:ban task is for and how to use it. See also magento/magento2#4106 94 | desc 'Add ban to Varnish for url(s)' 95 | task :ban do 96 | on primary fetch(:magento_deploy_setup_role) do 97 | # TODO: Document use of :ban_pools and :varnish_cache_hosts in project config file 98 | next unless any? :ban_pools 99 | next unless any? :varnish_cache_hosts 100 | 101 | within release_path do 102 | for pool in fetch(:ban_pools) do 103 | for cache_host in fetch(:varnish_cache_hosts) do 104 | execute :curl, %W{-s -H 'X-Pool: #{pool}' -X PURGE #{cache_host}} 105 | end 106 | end 107 | end 108 | end 109 | end 110 | end 111 | end 112 | 113 | namespace :composer do 114 | desc 'Run composer install' 115 | task :install => :auth_config do 116 | 117 | on release_roles :all do 118 | within release_path do 119 | composer_flags = '--prefer-dist --no-interaction' 120 | 121 | if fetch(:magento_deploy_no_dev) 122 | composer_flags += ' --no-dev' 123 | end 124 | 125 | if fetch(:magento_deploy_production) 126 | composer_flags += ' --optimize-autoloader' 127 | end 128 | 129 | execute :composer, "install #{composer_flags} 2>&1" 130 | 131 | if test "[ -f #{release_path}/update/composer.json ]" # can't count on this, but emit warning if not present 132 | execute :composer, "install #{composer_flags} -d ./update 2>&1" 133 | else 134 | puts "\e[0;31m Warning: ./update/composer.json does not exist in repository!\n\e[0m\n" 135 | end 136 | end 137 | end 138 | end 139 | 140 | desc 'Run composer dump-autoload' 141 | task 'dump-autoload' do 142 | 143 | on release_roles :all do 144 | within release_path do 145 | composer_flags = '--no-interaction' 146 | 147 | if fetch(:magento_deploy_no_dev) 148 | composer_flags += ' --no-dev' 149 | end 150 | 151 | if fetch(:magento_deploy_production) 152 | composer_flags += ' --optimize' 153 | end 154 | 155 | execute :composer, "dump-autoload #{composer_flags} 2>&1" 156 | end 157 | end 158 | end 159 | 160 | task :auth_config do 161 | on release_roles :all do 162 | within release_path do 163 | if fetch(:magento_auth_public_key) and fetch(:magento_auth_private_key) 164 | execute :composer, :config, '-q', 165 | fetch(:magento_auth_repo_name), 166 | fetch(:magento_auth_public_key), 167 | fetch(:magento_auth_private_key), 168 | verbosity: Logger::DEBUG 169 | end 170 | end 171 | end 172 | end 173 | end 174 | 175 | namespace :deploy do 176 | namespace :mode do 177 | desc "Enables production mode" 178 | task :production do 179 | on release_roles(:all), in: :sequence, wait: 1 do 180 | within release_path do 181 | execute :magento, "deploy:mode:set production --skip-compilation" 182 | end 183 | end 184 | end 185 | 186 | desc "Displays current application mode" 187 | task :show do 188 | on release_roles :all do 189 | within release_path do 190 | execute :magento, "deploy:mode:show" 191 | end 192 | end 193 | end 194 | end 195 | 196 | task :check do 197 | on release_roles :all do 198 | next unless any? :linked_files_touch 199 | on release_roles :all do |host| 200 | join_paths(shared_path, fetch(:linked_files_touch)).each do |file| 201 | unless test "[ -f #{file} ]" 202 | execute :touch, file 203 | end 204 | end 205 | end 206 | end 207 | end 208 | 209 | task :verify do 210 | is_err = false 211 | on release_roles :all do 212 | unless test "[ -f #{release_path}/app/etc/config.php ]" 213 | error "\e[0;31mThe repository is missing app/etc/config.php. Please install the application and retry!\e[0m" 214 | exit 1 # only need to check the repo once, so we immediately exit 215 | end 216 | 217 | # Checking app/etc/env.php in shared_path vs release_path to support the zero-side-effect 218 | # builds as implemented in the :detect_scd_config hook of deploy.rake 219 | unless test %Q[#{SSHKit.config.command_map[:php]} -r ' 220 | $cfg = include "#{shared_path}/app/etc/env.php"; 221 | exit((int)!isset($cfg["install"]["date"])); 222 | '] 223 | error "\e[0;31mError on #{host}:\e[0m No environment configuration could be found." + 224 | " Please configure app/etc/env.php and retry!" 225 | is_err = true 226 | end 227 | end 228 | exit 1 if is_err 229 | end 230 | end 231 | 232 | namespace :setup do 233 | desc 'Updates the module load sequence and upgrades database schemas and data fixtures' 234 | task :upgrade do 235 | on primary fetch(:magento_deploy_setup_role) do 236 | within release_path do 237 | warn "\e[0;31mWarning: Use of magento:setup:upgrade on production systems is discouraged." + 238 | " See https://github.com/davidalger/capistrano-magento2/issues/34 for details.\e[0m\n" 239 | 240 | execute :magento, 'setup:upgrade --keep-generated' 241 | end 242 | end 243 | end 244 | 245 | namespace :db do 246 | desc 'Checks if DB schema or data requires upgrade' 247 | task :status do 248 | on primary fetch(:magento_deploy_setup_role) do 249 | within release_path do 250 | execute :magento, 'setup:db:status' 251 | end 252 | end 253 | end 254 | 255 | task :upgrade do 256 | on primary fetch(:magento_deploy_setup_role) do 257 | within release_path do 258 | db_status = capture :magento, 'setup:db:status --no-ansi', verbosity: Logger::INFO 259 | 260 | if not db_status.to_s.include? 'All modules are up to date' 261 | execute :magento, 'setup:db-schema:upgrade' 262 | execute :magento, 'setup:db-data:upgrade' 263 | end 264 | end 265 | end 266 | end 267 | 268 | desc 'Upgrades data fixtures' 269 | task 'schema:upgrade' do 270 | on primary fetch(:magento_deploy_setup_role) do 271 | within release_path do 272 | execute :magento, 'setup:db-schema:upgrade' 273 | end 274 | end 275 | end 276 | 277 | desc 'Upgrades database schema' 278 | task 'data:upgrade' do 279 | on primary fetch(:magento_deploy_setup_role) do 280 | within release_path do 281 | execute :magento, 'setup:db-data:upgrade' 282 | end 283 | end 284 | end 285 | end 286 | 287 | desc 'Sets proper permissions on application' 288 | task :permissions do 289 | on release_roles :all do 290 | within release_path do 291 | execute :find, release_path, "-type d ! -perm #{fetch(:magento_deploy_chmod_d).to_i} -exec chmod #{fetch(:magento_deploy_chmod_d).to_i} {} +" 292 | execute :find, release_path, "-type f ! -perm #{fetch(:magento_deploy_chmod_f).to_i} -exec chmod #{fetch(:magento_deploy_chmod_f).to_i} {} +" 293 | 294 | fetch(:magento_deploy_chmod_x).each() do |file| 295 | execute :chmod, "+x #{release_path}/#{file}" 296 | end 297 | end 298 | end 299 | end 300 | 301 | desc 'Sets proper selinux context on directories which are written to by web processes' 302 | task :selinux do 303 | on release_roles :all do 304 | with path: '/usr/sbin:$PATH' do 305 | if test "selinuxenabled" 306 | within release_path do 307 | fetch(:magento_deploy_chcon_dirs).each() do |dir| 308 | execute :chcon, "-RP -t #{fetch(:magento_deploy_chcon_type)} #{release_path}/#{dir}" 309 | end 310 | end 311 | end 312 | end 313 | end 314 | end 315 | 316 | namespace :di do 317 | desc 'Runs dependency injection compilation routine' 318 | task :compile do 319 | on release_roles :all do 320 | within release_path do 321 | with mage_mode: :production do 322 | execute :magento, "setup:di:compile" 323 | end 324 | end 325 | end 326 | end 327 | end 328 | 329 | namespace 'static-content' do 330 | desc 'Deploys static view files' 331 | task :deploy do 332 | on release_roles :all do 333 | with mage_mode: :production do 334 | deploy_languages = fetch(:magento_deploy_languages) 335 | if deploy_languages.count() > 0 336 | deploy_languages = deploy_languages.join(' ').prepend(' ') 337 | else 338 | deploy_languages = nil 339 | end 340 | 341 | deploy_themes = fetch(:magento_deploy_themes) 342 | if deploy_themes.count() > 0 343 | deploy_themes = deploy_themes.join(' -t ').prepend(' -t ') 344 | else 345 | deploy_themes = nil 346 | end 347 | 348 | deploy_jobs = fetch(:magento_deploy_jobs) 349 | if deploy_jobs 350 | deploy_jobs = " --jobs #{deploy_jobs}" 351 | else 352 | deploy_jobs = nil 353 | end 354 | 355 | # Static content compilation strategies that can be one of the following: 356 | # quick (default), standard (like previous versions) or compact 357 | compilation_strategy = fetch(:magento_deploy_strategy) 358 | if compilation_strategy 359 | compilation_strategy = " -s #{compilation_strategy}" 360 | end 361 | 362 | within release_path do 363 | execute :magento, "setup:static-content:deploy#{compilation_strategy}#{deploy_jobs}#{deploy_languages}#{deploy_themes}" 364 | end 365 | 366 | # Set the deployed_version of static content to ensure it matches across all hosts 367 | upload!(StringIO.new(deployed_version), "#{release_path}/pub/static/deployed_version.txt") 368 | end 369 | end 370 | end 371 | end 372 | end 373 | 374 | namespace :maintenance do 375 | desc 'Enable maintenance mode' 376 | task :enable do 377 | on release_roles :all do 378 | within release_path do 379 | execute :magento, 'maintenance:enable' 380 | end 381 | end 382 | end 383 | 384 | # Internal command used to check if maintenance mode is neeeded and disable when zero-down deploy is 385 | # possible or when maintenance mode was previously enabled on the deploy target 386 | task :check do 387 | on primary fetch(:magento_deploy_setup_role) do 388 | maintenance_enabled = nil 389 | disable_maintenance = false # Do not disable maintenance mode in absence of positive release checks 390 | 391 | if test "[ -d #{current_path} ]" 392 | within current_path do 393 | # If maintenance mode is already enabled, enable maintenance mode on new release and disable management to 394 | # avoid disabling maintenance mode in the event it was manually enabled prior to deployment 395 | info "Checking maintenance status..." 396 | maintenance_status = capture :magento, 'maintenance:status', raise_on_non_zero_exit: false 397 | 398 | if maintenance_status.to_s.include? 'maintenance mode is active' 399 | info "Maintenance mode is currently active." 400 | maintenance_enabled = true 401 | else 402 | info "Maintenance mode is currently inactive." 403 | maintenance_enabled = false 404 | end 405 | info "" 406 | end 407 | end 408 | 409 | # If maintenance is currently active, enable it on the newly deployed release 410 | if maintenance_enabled 411 | info "Enabling maintenance mode on new release to match active status of current release." 412 | on release_roles :all do 413 | within release_path do 414 | execute :magento, 'maintenance:enable' 415 | end 416 | end 417 | info "" 418 | end 419 | 420 | within release_path do 421 | info "Checking database status..." 422 | # Check setup:db:status output and if out-of-date do not disable maintenance mode 423 | database_status = capture :magento, 'setup:db:status', raise_on_non_zero_exit: false 424 | database_uptodate = false 425 | 426 | if database_status.to_s.include? 'All modules are up to date' 427 | info "All modules are up to date." 428 | info "" 429 | database_uptodate = true 430 | else 431 | puts " #{database_status.gsub("\n", "\n ").sub(" Run 'setup:upgrade' to update your DB schema and data.", "")}" 432 | end 433 | 434 | # Check app:config:status output and if out-of-date do not disable maintenance mode 435 | info "Checking config status..." 436 | config_status = capture :magento, 'app:config:status', raise_on_non_zero_exit: false 437 | config_uptodate = false 438 | 439 | if config_status.to_s.include? 'Config files are up to date' 440 | info "Config files are up to date." 441 | config_uptodate = true 442 | else 443 | puts " #{config_status.gsub("\n", "\n ").sub(" Run app:config:import or setup:upgrade command to synchronize configuration.", "")}" 444 | end 445 | info "" 446 | 447 | # If both checks above reported up-to-date status checks disable maintenance mode 448 | if database_uptodate and config_uptodate 449 | disable_maintenance = true 450 | end 451 | 452 | if maintenance_enabled 453 | info "Disabling maintenance mode management..." 454 | info "Maintenance mode was already active prior to deploy." 455 | set :magento_deploy_maintenance, false 456 | elsif disable_maintenance 457 | info "Disabling maintenance mode management..." 458 | info "There are no database updates or config changes. This is a zero-down deployment." 459 | set :magento_internal_zero_down_flag, true # Set internal flag to stop db schema/data upgrades from running 460 | set :magento_deploy_maintenance, false # Disable maintenance mode management since it is not neccessary 461 | else 462 | info "Maintenance mode usage will be enforced per :magento_deploy_maintenance (setting is #{fetch(:magento_deploy_maintenance).to_s})" 463 | end 464 | end 465 | end 466 | end 467 | 468 | desc 'Disable maintenance mode' 469 | task :disable do 470 | on release_roles :all do 471 | within release_path do 472 | execute :magento, 'maintenance:disable' 473 | end 474 | end 475 | end 476 | 477 | desc 'Displays maintenance mode status' 478 | task :status do 479 | on release_roles :all do 480 | within release_path do 481 | execute :magento, 'maintenance:status' 482 | end 483 | end 484 | end 485 | 486 | desc 'Sets maintenance mode exempt IPs' 487 | task 'allow-ips', :ip do |t, args| 488 | on release_roles :all do 489 | within release_path do 490 | execute :magento, 'maintenance:allow-ips', args[:ip] 491 | end 492 | end 493 | end 494 | end 495 | 496 | namespace :indexer do 497 | desc 'Reindex data by all indexers' 498 | task :reindex do 499 | on primary fetch(:magento_deploy_setup_role) do 500 | within release_path do 501 | execute :magento, 'indexer:reindex' 502 | end 503 | end 504 | end 505 | 506 | desc 'Shows allowed indexers' 507 | task :info do 508 | on primary fetch(:magento_deploy_setup_role) do 509 | within release_path do 510 | execute :magento, 'indexer:info' 511 | end 512 | end 513 | end 514 | 515 | desc 'Shows status of all indexers' 516 | task :status do 517 | on primary fetch(:magento_deploy_setup_role) do 518 | within release_path do 519 | execute :magento, 'indexer:status' 520 | end 521 | end 522 | end 523 | 524 | desc 'Shows mode of all indexers' 525 | task 'show-mode', :index do |t, args| 526 | on primary fetch(:magento_deploy_setup_role) do 527 | within release_path do 528 | execute :magento, 'indexer:show-mode', args[:index] 529 | end 530 | end 531 | end 532 | 533 | desc 'Sets mode of all indexers' 534 | task 'set-mode', :mode, :index do |t, args| 535 | on primary fetch(:magento_deploy_setup_role) do 536 | within release_path do 537 | execute :magento, 'indexer:set-mode', args[:mode], args[:index] 538 | end 539 | end 540 | end 541 | end 542 | end 543 | -------------------------------------------------------------------------------- /lib/capistrano/tasks/notifier.rake: -------------------------------------------------------------------------------- 1 | ## 2 | # Copyright © 2016 by David Alger. All rights reserved 3 | # 4 | # Licensed under the Open Software License 3.0 (OSL-3.0) 5 | # See included LICENSE file for full text of OSL-3.0 6 | # 7 | # http://davidalger.com/contact/ 8 | ## 9 | 10 | require 'terminal-notifier' 11 | 12 | namespace :deploy do 13 | after 'deploy:failed', :notify_user_failure do 14 | run_locally do 15 | set :message, "ERROR in deploying " + fetch(:application).to_s + " to " + fetch(:stage).to_s 16 | TerminalNotifier.notify(fetch(:message), :title => 'Capistrano') 17 | end 18 | end 19 | 20 | after :finished, :notify_user do 21 | run_locally do 22 | set :message, "Finished deploying " + fetch(:application).to_s + " to " + fetch(:stage).to_s 23 | TerminalNotifier.notify(fetch(:message), :title => 'Capistrano') 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /lib/capistrano/tasks/pending.rake: -------------------------------------------------------------------------------- 1 | ## 2 | # Copyright © 2016 by David Alger. All rights reserved 3 | # 4 | # Licensed under the Open Software License 3.0 (OSL-3.0) 5 | # See included LICENSE file for full text of OSL-3.0 6 | # 7 | # http://davidalger.com/contact/ 8 | ## 9 | 10 | include Capistrano::Magento2::Pending 11 | 12 | before 'deploy:check', 'deploy:pending:warn' 13 | 14 | namespace :deploy do 15 | desc "Displays a summary of commits pending deployment" 16 | task :pending => 'deploy:pending:log' 17 | 18 | namespace :pending do 19 | task :warn => :log do 20 | if fetch(:magento_deploy_pending_warn) 21 | need_warning = true 22 | 23 | on roles fetch(:magento_deploy_pending_role) do |host| 24 | has_revision = ensure_revision do 25 | # if any host has a change in revision, do not warn user 26 | need_warning = false if from_rev != to_rev 27 | end 28 | 29 | # if a host does not have a revision, do not warn user 30 | need_warning = false if not has_revision 31 | end 32 | 33 | # if there is nothing to deploy on any host, prompt user for confirmation 34 | if need_warning 35 | print " Are you sure you want to continue? [y/n] \e[0m" 36 | 37 | proceed = STDIN.gets[0..0] rescue nil 38 | exit unless proceed == 'y' || proceed == 'Y' 39 | end 40 | end 41 | end 42 | 43 | task :log do 44 | on roles fetch(:magento_deploy_pending_role) do |host| 45 | ensure_revision true do 46 | # update local repository to ensure accuracy of report 47 | run_locally do 48 | execute :git, :fetch, :origin 49 | end 50 | 51 | # fetch current revision and revision to be deployed 52 | from = from_rev 53 | to = to_rev 54 | 55 | # if there is nothing to deploy on this host, inform the user 56 | if from == to 57 | info "\e[0;31mNo changes to deploy on #{host} (from and to are the same: #{from} -> #{to})\e[0m" 58 | else 59 | run_locally do 60 | header = "\e[0;90mChanges pending deployment on #{host} (#{from} -> #{to}):\e[0m\n" 61 | 62 | # capture log of commits between current revision and revision for deploy 63 | output = capture :git, :log, "#{from}..#{to}", fetch(:magento_deploy_pending_format) 64 | 65 | # if we get no results, flip refs to look at reverse log in case of rollback deployments 66 | if output.to_s.strip.empty? 67 | output = capture :git, :log, "#{to}..#{from}", fetch(:magento_deploy_pending_format) 68 | if not output.to_s.strip.empty? 69 | header += "\e[0;31mWarning: It appears you may be going backwards in time on #{host} with this deployment!\e[0m\n" 70 | end 71 | end 72 | 73 | # write pending changes log 74 | (header + output).each_line do |line| 75 | info line 76 | end 77 | end 78 | end 79 | end 80 | end 81 | end 82 | end 83 | end 84 | --------------------------------------------------------------------------------