diff --git a/CHANGELOG.md b/CHANGELOG.md index a950e3e..76719af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,52 @@ # Capistrano::Magento2 Change Log +0.6.2 +========== + +* Added setting `:magento_deploy_jobs` to support configuring number of parallel static content deployment tasks +* Fixed issue where ./update dir may exist without a composer.json file, causing deployment failure +* Updated uses of bin/magento where output is parsed to include `--no-ansi` to eliminate potential failures +* Improved error reporting on static content deployment failure + +0.6.1 +========== + +* Fixed Magento version check failing on some servers due to ansi output in non-interactive shells (issue #64) +* Added ability to configure Magento's composer authentication keys. See README for details (PR #56) +* Changed pending change log to hook into before `deploy:check` (previously hooked before `deploy`) + +0.6.0 +========== + +* Added full-featured pending change logging functionality. See README for details (issue #58) +* Fixed inability to set PATH in capistrano configuration vs `.bashrc` file (issue #62) +* Updated README to reflect removing the `terminal-notifier` gem as a hard dependency (issue #19) +* Removed `capistrano-pending` as a dependency (issue #58) + +0.5.9 +========== + +* Updated README with Capistrano 3.7 setup information +* Updated `linked_dirs` to link `pub/sitemaps` by default in similar fashion to the Magento1 deployment gem +* Updated README with guidance on adding a path to the list of `linked_dirs` without copying the entire configuration forward +* Fixed bug causing pipefail option to persist after `Capistrano::Magento2::Setup.static_content_deploy` is called + +0.5.8 +========== + +* Fixed critical failure due to command map being broken in v0.5.7 updates (issue #50, issue #51) + +0.5.7 +========== +_Note: This release was yanked from RubyGems due to a critical failure in the deploy routine._ + +* Fixed failing deploys for Magento 2.1.0 caused by improper version checks on flags added in version 2.1.1 (issue #45) +* Fixed failure to detect error codes Magento 2.1.1 returns on a failed static-content deploy job (issue #44) + 0.5.6 ========== -* Fixed issue where setup:di:compile failing to return an exit code caused DI compilation failures to be masked +* Fixed issue where setup:di:compile failing to return an exit code caused DI compilation failures to be masked (issue #41) 0.5.5 ========== diff --git a/README.md b/README.md index a9f8991..740176a 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,11 @@ _Note: By default, Capistrano creates "staging" and "production" stages. If you # Load Magento deployment tasks require 'capistrano/magento2/deploy' + require 'capistrano/magento2/pending' + + # Load Git plugin + require "capistrano/scm/git" + install_plugin Capistrano::SCM::Git # Load custom tasks from `lib/capistrano/tasks` if you have any defined Dir.glob('lib/capistrano/tasks/*.rake').each { |r| import r } @@ -114,7 +119,8 @@ Before you can use Capistrano to deploy, you must configure the `config/deploy.r | `:magento_deploy_setup_role` | `:all` | Role from which primary host is chosen to run things like setup:upgrade on | `:magento_deploy_cache_shared` | `true` | If true, cache operations are restricted to the primary node in setup role | `:magento_deploy_languages` | `['en_US']` | Array of languages passed to static content deploy routine -| `:magento_deploy_themes` | `[]` | Array of themes passed to static content deploy routine (Magento 2.1+ only) +| `:magento_deploy_themes` | `[]` | Array of themes passed to static content deploy (Magento 2.1.1 and later) +| `:magento_deploy_jobs` | `4` | Number of threads to use for static content deploy (Magento 2.1.1 and later) | `:magento_deploy_composer` | `true` | Enables composer install behaviour in the built-in deploy routine | `:magento_deploy_production` | `true` | Enables production specific DI compilation and static content generation | `:magento_deploy_maintenance` | `true` | Enables use of maintenance mode while magento:setup:upgrade runs @@ -143,12 +149,12 @@ For the sake of simplicity in new project setups `:linked_dirs` and `:linked_fil set :linked_files, [ 'app/etc/env.php', 'var/.setup_cronjob_status', - 'var/.update_cronjob_status', - 'pub/sitemap.xml' + 'var/.update_cronjob_status' ] set :linked_dirs, [ - 'pub/media', + 'pub/media', + 'pub/sitemaps', 'var/backups', 'var/composer_home', 'var/importexport', @@ -159,7 +165,24 @@ set :linked_dirs, [ ] ``` -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. +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: + +```ruby +append :linked_dirs, 'path/to/link' +``` + +### Composer Auth Credentials + +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: + +```ruby +set :magento_auth_public_key, '' +set :magento_auth_private_key, '' +``` + +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) + +**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. ### Magento 2 Deploy Routine @@ -171,7 +194,7 @@ To see what process the built-in routine runs, take a look at the included rake ### Web Server Root Path -Before deploying with Capistrano, you must update each of your web servers to point to a `current` directory inside of the `:deploy_to` directory. For example: `/var/www/html/current` Refer to the [Capistrano Structure](http://capistranorb.com/documentation/getting-started/structure/) to learn more about Capistrano's folder structure. +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. ## Magento Specific Tasks @@ -200,21 +223,64 @@ All Magento 2 tasks used by the built-in `deploy.rake` file as well as some addi | magento:setup:static-content:deploy | Deploys static view files | | magento:setup:upgrade | Run the Magento upgrade process | -## Terminal Notifier on OS X -This gem specifies [terminal-notifier](https://rubygems.org/gems/terminal-notifier) as a dependency in order to support notifications on OS X via an optional include. To use the built-in notifications, add the following line to your `Capfile`: +## Pending Changes Support + +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: + +``` +00:00 deploy:pending:log + 01 git fetch origin + ✔ 01 dalger@localhost 1.241s + ✔ 01 dalger@localhost 1.259s + Changes pending deployment on web1 (tags/2.1.2 -> 2.1): + 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 + 7fb219c Thu Feb 23 12:17:11 2017 -0600 David Alger (tag: 2.1.3) Magento 2.1.3 + 570c9b3 Thu Feb 23 12:12:43 2017 -0600 David Alger Updated capistrano configuration + No changes to deploy on web2 (from and to are the same: 2.1 -> 2.1) +``` + +When there are no changes due for deployment to any host, a warning requiring confirmation will be emitted by default: + +``` +No changes to deploy on web1 (from and to are the same: 2.1 -> 2.1) +No changes to deploy on web2 (from and to are the same: 2.1 -> 2.1) +Are you sure you want to continue? [y/n] +``` + +This confirmational warning can be disabled by including the following in your project's configuration: ```ruby -require 'capistrano/magento2/notifier' +set :magento_deploy_pending_warn, false ``` -## Pending Changes +### Pending Changes Configuration -This gem specifies [capistrano-pending](https://rubygems.org/gems/capistrano-pending) as a dependency and adds some (optional) custom functionality on top of that gem: Any time the `deploy` command is run, a one line summary of git commits that will be deployed will be displayed. If the server(s) you are deploying to already have the latest changes, you will be warned of this and a prompt will appear confirming that you want to continue deploying. +| setting | what it does +| -------------------------------- | ------- | --- +| `:magento_deploy_pending_role` | Role to check for pending changes on; defaults to `:all` +| `:magento_deploy_pending_warn` | Set this to `false` to disable confirmational warning on zero-change deployments +| `:magento_deploy_pending_format` | Can be used to set a custom change log format; refer to `defaults.rb` for example + +### Pending Changes Tasks + +| cap command | what it does | +| ------------------------------------- | -------------------------------------------------- | +| deploy:pending | Displays a summary of commits pending deployment | + +Note: For more details including screenshots of what this functionality does, reference [this post](https://github.com/davidalger/capistrano-magento2/issues/58#issuecomment-282404477). + +## Terminal Notifier on OS X + +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`: + +```ruby +require 'capistrano/magento2/notifier' +``` -To add the `capistrano-pending` gem and additional functionality to you project, add the following line to your `Capfile`: +**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`: ```ruby -require 'capistrano/magento2/pending' +gem 'terminal-notifier' ``` ## Development diff --git a/capistrano-magento2.gemspec b/capistrano-magento2.gemspec index b52794b..4f543b9 100644 --- a/capistrano-magento2.gemspec +++ b/capistrano-magento2.gemspec @@ -29,10 +29,6 @@ Gem::Specification.new do |spec| spec.add_dependency 'capistrano', '~> 3.1' - # TODO explore removing these from gemspec per issue #19 - spec.add_dependency 'terminal-notifier', '~> 1.6' - spec.add_dependency 'capistrano-pending', '~> 0.1' - spec.add_development_dependency 'bundler', '~> 1.7' spec.add_development_dependency 'rake', '~> 10.0' end diff --git a/lib/capistrano/magento2.rb b/lib/capistrano/magento2.rb index 1aa3cf7..cc85b84 100644 --- a/lib/capistrano/magento2.rb +++ b/lib/capistrano/magento2.rb @@ -13,11 +13,11 @@ module Capistrano module Magento2 module Helpers def magento_version - return (capture "/usr/bin/env php -f #{release_path}/bin/magento -- -V").split(' ').pop.to_f + return Gem::Version::new((capture :php, "-f #{release_path}/bin/magento -- -V --no-ansi").split(' ').pop) end def disabled_modules - output = capture :magento, 'module:status' + output = capture :magento, 'module:status --no-ansi' output = output.split("disabled modules:\n", 2)[1] if output == nil or output.strip == "None" @@ -29,21 +29,38 @@ def disabled_modules def cache_hosts return fetch(:magento_deploy_cache_shared) ? (primary fetch :magento_deploy_setup_role) : (release_roles :all) end + + # Set pipefail allowing console exit codes in Magento 2.1.1 and later to halt execution when using pipes + def Helpers.set_pipefail + if not SSHKit.config.command_map[:magento].include? 'set -o pipefail' # avoids trouble on multi-host deploys + @@pipefail_less = SSHKit.config.command_map[:magento].dup + SSHKit.config.command_map[:magento] = "set -o pipefail; #{@@pipefail_less}" + end + end + + # Reset the command map without prefix, removing pipefail option so it won't affect other commands + def Helpers.unset_pipefail + SSHKit.config.command_map[:magento] = @@pipefail_less + end end - + module Setup def static_content_deploy params + Helpers.set_pipefail output = capture :magento, - "setup:static-content:deploy #{params} | stdbuf -o0 tr -d .", + "setup:static-content:deploy --no-ansi #{params} | stdbuf -o0 tr -d .", verbosity: Logger::INFO + Helpers.unset_pipefail + # String based error checking is here to catch errors in Magento 2.1.0 and earlier; later versions will exit + # immediately when a console exit code is retruned, never evaluating this code. if not output.to_s.include? 'New version of deployed files' - raise Exception, "\e[0;31mFailed to compile static assets\e[0m" + raise Exception, "\e[0;31mFailed to compile static assets. No new version found in command output!\e[0m" end output.to_s.each_line { |line| if line.split('errors: ', 2).pop.to_i > 0 - raise Exception, "\e[0;31mFailed to compile static assets\e[0m" + raise Exception, "\e[0;31mFailed to compile static assets. Errors found in command output: #{line}\e[0m" end } end diff --git a/lib/capistrano/magento2/defaults.rb b/lib/capistrano/magento2/defaults.rb index aed0335..4925bb8 100644 --- a/lib/capistrano/magento2/defaults.rb +++ b/lib/capistrano/magento2/defaults.rb @@ -10,19 +10,18 @@ set :linked_files, fetch(:linked_files, []).push( 'app/etc/env.php', 'var/.setup_cronjob_status', - 'var/.update_cronjob_status', - 'pub/sitemap.xml' + 'var/.update_cronjob_status' ) set :linked_files_touch, fetch(:linked_files_touch, []).push( 'app/etc/env.php', 'var/.setup_cronjob_status', - 'var/.update_cronjob_status', - 'pub/sitemap.xml' + 'var/.update_cronjob_status' ) set :linked_dirs, fetch(:linked_dirs, []).push( - 'pub/media', + 'pub/media', + 'pub/sitemaps', 'var/backups', 'var/composer_home', 'var/importexport', @@ -32,6 +31,11 @@ 'var/tmp' ) +# magento composer repository auth credentials +set :magento_auth_repo_name, fetch(:magento_auth_repo_name, 'http-basic.repo.magento.com') +set :magento_auth_public_key, fetch(:magento_auth_public_key, false) +set :magento_auth_private_key, fetch(:magento_auth_private_key, false) + # deploy permissions defaults set :magento_deploy_chmod_d, fetch(:magento_deploy_chmod_d, '2770') set :magento_deploy_chmod_f, fetch(:magento_deploy_chmod_f, '0660') @@ -44,7 +48,16 @@ set :magento_deploy_maintenance, fetch(:magento_deploy_maintenance, true) set :magento_deploy_production, fetch(:magento_deploy_production, true) set :magento_deploy_themes, fetch(:magento_deploy_themes, []) +set :magento_deploy_jobs, fetch(:magento_deploy_jobs, nil) # this defaults to 4 when supported by bin/magento # deploy targetting defaults set :magento_deploy_setup_role, fetch(:magento_deploy_setup_role, :all) set :magento_deploy_cache_shared, fetch(:magento_deploy_cache_shared, true) + +# pending deploy check defaults +set :magento_deploy_pending_role, fetch(:magento_deploy_pending_role, :all) +set :magento_deploy_pending_warn, fetch(:magento_deploy_pending_warn, true) +set :magento_deploy_pending_format, fetch( + :magento_deploy_pending_format, + '--pretty="format:%C(yellow)%h %Cblue%>(12)%ad %Cgreen%<(7)%aN%Cred%d %Creset%s"' +) diff --git a/lib/capistrano/magento2/pending.rb b/lib/capistrano/magento2/pending.rb index 90606fe..ea955cc 100644 --- a/lib/capistrano/magento2/pending.rb +++ b/lib/capistrano/magento2/pending.rb @@ -8,46 +8,42 @@ ## require 'capistrano/deploy' -require 'capistrano/pending/scm/base' +require 'capistrano/magento2' module Capistrano - module Pending - module SCM - class Git < Base - - # Enhance capistrano-pending gem's native deploy:pending:log command by updating repository and then - # showing the actual changes that will be deployed. Also changes log output to oneline for easy reading - # - # Params: - # +from+ - commit-ish to compare from - # +to+ - commit-ish to compare to - # +returnOutput+ - whether to return or print the output - # - def log(from, to, returnOutput=false) + module Magento2 + module Pending + def ensure_revision inform_user = false + if test "[ -f #{current_path}/REVISION ]" + yield + else + warn "\e[0;31mSkipping pending changes check on #{host} (no REVISION file found)\e[0m" if inform_user + return false + end + return true + end + + def from_rev + within current_path do + current_revision = capture(:cat, "REVISION") + run_locally do - execute :git, :fetch, :origin # update repository to ensure accuracy of pending changes report - - # Since the :branch to deploy from may be behind the upstream branch, get name of upstream branch - # and use it for comparison. We are using the test command in case the :branch is set to a specific - # commit hash, in which case there is no upstream branch. - - if test(:git, 'rev-parse', '--abbrev-ref', '--symbolic-full-name', to + '@{u}') - to = capture(:git, 'rev-parse', '--abbrev-ref', '--symbolic-full-name', to + '@{u}') - end - - output = capture( - :git, - :log, - "#{from}..#{to}", - '--pretty="format:%C(yellow)%h %Cblue%>(12)%ad %Cgreen%<(7)%aN%Cred%d %Creset%s"' - ) - - if returnOutput - return output - else - puts output - end + return capture(:git, "name-rev --always --name-only #{current_revision}") # find symbolic name for ref + end + end + end + + def to_rev + run_locally do + to = fetch(:branch) + + # get target branch upstream if there is one + if test(:git, "rev-parse --abbrev-ref --symbolic-full-name #{to}@{u}") + to = capture(:git, "rev-parse --abbrev-ref --symbolic-full-name #{to}@{u}") end + + # find symbolic name for revision + to = capture(:git, "name-rev --always --name-only #{to}") end end end diff --git a/lib/capistrano/magento2/version.rb b/lib/capistrano/magento2/version.rb index 4ea010a..2cbf8e3 100644 --- a/lib/capistrano/magento2/version.rb +++ b/lib/capistrano/magento2/version.rb @@ -9,6 +9,6 @@ module Capistrano module Magento2 - VERSION = '0.5.6' + VERSION = '0.6.2' end end diff --git a/lib/capistrano/tasks/magento.rake b/lib/capistrano/tasks/magento.rake index fca683b..abef8af 100644 --- a/lib/capistrano/tasks/magento.rake +++ b/lib/capistrano/tasks/magento.rake @@ -81,7 +81,7 @@ namespace :magento do namespace :composer do desc 'Run composer install' - task :install do + task :install => :auth_config do on release_roles :all do within release_path do @@ -93,15 +93,29 @@ namespace :magento do execute :composer, "install #{composer_flags} 2>&1" - if fetch(:magento_deploy_production) and magento_version > 2.0 + if fetch(:magento_deploy_production) and magento_version >= Gem::Version.new('2.1') composer_flags += ' --no-dev' execute :composer, "install #{composer_flags} 2>&1" # removes require-dev components from prev command end - if test "[ -d #{release_path}/update ]" # can't count on this, but emit warning if not present + if test "[ -f #{release_path}/update/composer.json ]" # can't count on this, but emit warning if not present execute :composer, "install #{composer_flags} -d ./update 2>&1" else - puts "\e[0;31m Warning: ./update dir does not exist in repository!\n\e[0m\n" + puts "\e[0;31m Warning: ./update/composer.json does not exist in repository!\n\e[0m\n" + end + end + end + end + + task :auth_config do + on release_roles :all do + within release_path do + if fetch(:magento_auth_public_key) and fetch(:magento_auth_private_key) + execute :composer, :config, '-q', + fetch(:magento_auth_repo_name), + fetch(:magento_auth_public_key), + fetch(:magento_auth_private_key), + verbosity: Logger::DEBUG end end end @@ -169,8 +183,8 @@ namespace :magento do task :upgrade do on primary fetch(:magento_deploy_setup_role) do within release_path do - db_status = capture :magento, 'setup:db:status', verbosity: Logger::INFO - + db_status = capture :magento, 'setup:db:status --no-ansi', verbosity: Logger::INFO + if not db_status.to_s.include? 'All modules are up to date' execute :magento, 'setup:db-schema:upgrade' execute :magento, 'setup:db-data:upgrade' @@ -222,9 +236,9 @@ namespace :magento do # we have to use multi-tenant currently. However, the multi-tenant is being dropped in 2.1 and is no longer # present in the develop mainline, so we are testing for multi-tenant presence for long-term portability. if test :magento, 'setup:di:compile-multi-tenant --help >/dev/null 2>&1' - output = capture :magento, 'setup:di:compile-multi-tenant', verbosity: Logger::INFO + output = capture :magento, 'setup:di:compile-multi-tenant --no-ansi', verbosity: Logger::INFO else - output = capture :magento, 'setup:di:compile', verbosity: Logger::INFO + output = capture :magento, 'setup:di:compile --no-ansi', verbosity: Logger::INFO end # 2.0.x never returns a non-zero exit code for errors, so manually check string @@ -245,16 +259,26 @@ namespace :magento do deploy_languages = fetch(:magento_deploy_languages).join(' ') deploy_themes = fetch(:magento_deploy_themes) + deploy_jobs = fetch(:magento_deploy_jobs) - if deploy_themes.count() > 0 and _magento_version >= 2.1 + if deploy_themes.count() > 0 and _magento_version >= Gem::Version.new('2.1.1') deploy_themes = deploy_themes.join(' -t ').prepend(' -t ') elsif deploy_themes.count() > 0 - warn "\e[0;31mWarning: Magento 2.0 does not support :magento_deploy_themes setting (ignoring value)\e[0m" + warn "\e[0;31mWarning: the :magento_deploy_themes setting is only supported in Magento 2.1.1 and later\e[0m" deploy_themes = nil else deploy_themes = nil end + if deploy_jobs and _magento_version >= Gem::Version.new('2.1.1') + deploy_jobs = "--jobs #{deploy_jobs} " + elsif deploy_jobs + warn "\e[0;31mWarning: the :magento_deploy_jobs setting is only supported in Magento 2.1.1 and later\e[0m" + deploy_jobs = nil + else + deploy_jobs = nil + end + # Output is being checked for a success message because this command may easily fail due to customizations # and 2.0.x CLI commands do not return error exit codes on failure. See magento/magento2#3060 for details. within release_path do @@ -263,18 +287,18 @@ namespace :magento do execute "touch #{release_path}/pub/static/deployed_version.txt" # Generates all but the secure versions of RequireJS configs - static_content_deploy "#{deploy_languages}#{deploy_themes}" + static_content_deploy "#{deploy_jobs}#{deploy_languages}#{deploy_themes}" end # Run again with HTTPS env var set to 'on' to pre-generate secure versions of RequireJS configs deploy_flags = ['javascript', 'css', 'less', 'images', 'fonts', 'html', 'misc', 'html-minify'] .join(' --no-').prepend(' --no-'); - # Magento 2.0 does not have these flags, so only way to generate secure files is to do all of them :/ - deploy_flags = nil if _magento_version <= 2.0 + # Magento 2.1.0 and earlier lack support for these flags, so generation of secure files requires full re-run + deploy_flags = nil if _magento_version <= Gem::Version.new('2.1.0') within release_path do with(https: 'on') { - static_content_deploy "#{deploy_languages}#{deploy_themes}#{deploy_flags}" + static_content_deploy "#{deploy_jobs}#{deploy_languages}#{deploy_themes}#{deploy_flags}" } end end end diff --git a/lib/capistrano/tasks/pending.rake b/lib/capistrano/tasks/pending.rake index 3eca6ee..647f2cb 100644 --- a/lib/capistrano/tasks/pending.rake +++ b/lib/capistrano/tasks/pending.rake @@ -7,33 +7,73 @@ # http://davidalger.com/contact/ ## -require 'capistrano-pending' +include Capistrano::Magento2::Pending + +before 'deploy:check', 'deploy:pending:warn' -before :deploy, 'deploy:pending:check_changes' namespace :deploy do + desc "Displays a summary of commits pending deployment" + task :pending => 'deploy:pending:log' - # Check for pending changes on the primary node and then notify user of any incoming - # changes and/or warn that there is nothing to deploy namespace :pending do - task :check_changes do - on primary fetch(:magento_deploy_setup_role) do - # check for pending changes only if REVISION file exists to prevent error - if test "[ -f #{current_path}/REVISION ]" - invoke 'deploy:pending:setup' - from = fetch(:revision) - to = fetch(:branch) - - output = _scm.log(from, to, true) - if output.to_s.strip.empty? - puts "\e[0;31m No changes to deploy (from and to are the same: #{from}..#{to})" - print " Are you sure you want to continue? [y/n] \e[0m" - - proceed = STDIN.gets[0..0] rescue nil - exit unless proceed == 'y' || proceed == 'Y' + task :warn => :log do + if fetch(:magento_deploy_pending_warn) + need_warning = true + + on roles fetch(:magento_deploy_pending_role) do |host| + has_revision = ensure_revision do + # if any host has a change in revision, do not warn user + need_warning = false if from_rev != to_rev + end + + # if a host does not have a revision, do not warn user + need_warning = false if not has_revision + end + + # if there is nothing to deploy on any host, prompt user for confirmation + if need_warning + print " Are you sure you want to continue? [y/n] \e[0m" + + proceed = STDIN.gets[0..0] rescue nil + exit unless proceed == 'y' || proceed == 'Y' + end + end + end + + task :log do + on roles fetch(:magento_deploy_pending_role) do |host| + ensure_revision true do + # update local repository to ensure accuracy of report + run_locally do + execute :git, :fetch, :origin + end + + # fetch current revision and revision to be deployed + from = from_rev + to = to_rev + + # if there is nothing to deploy on this host, inform the user + if from == to + info "\e[0;31mNo changes to deploy on #{host} (from and to are the same: #{from} -> #{to})\e[0m" else - puts "\e[0;90m Deploying changes #{from}..#{to}:\e[0m" - output.each_line do |s| - puts " " + s + run_locally do + header = "\e[0;90mChanges pending deployment on #{host} (#{from} -> #{to}):\e[0m\n" + + # capture log of commits between current revision and revision for deploy + output = capture :git, :log, "#{from}..#{to}", fetch(:magento_deploy_pending_format) + + # if we get no results, flip refs to look at reverse log in case of rollback deployments + if output.to_s.strip.empty? + output = capture :git, :log, "#{to}..#{from}", fetch(:magento_deploy_pending_format) + if not output.to_s.strip.empty? + header += "\e[0;31mWarning: It appears you may be going backwards in time on #{host} with this deployment!\e[0m\n" + end + end + + # write pending changes log + (header + output).each_line do |line| + info line + end end end end