lib/hu/deploy.rb in hu-1.3.5 vs lib/hu/deploy.rb in hu-1.3.6

- old
+ new

@@ -11,10 +11,14 @@ require 'chronic_duration' require 'tempfile' require 'thread_safe' require 'io/console' require 'rugged' +require 'pty' +require 'thread' +require 'paint' +require 'lolcat/lol' module Hu class Cli < Optix::Cli class Deploy < Optix::Cli @@shutting_down = false @@ -201,11 +205,11 @@ puts "Phase 2/3: Your local "+"release/#{release_tag}".bright+" (formerly "+"develop".bright+") is now live at #{stag_app_name}." puts " Please test thoroughly: "+"#{app['web_url']}".bright puts " If everything looks good, you may proceed and finish the release." puts " If there are problems: Quit, delete the release branch and start fixing." puts - elsif git_revisions[prod_app_name] != git_revisions[stag_app_name] + elsif git_revisions[prod_app_name] != git_revisions[stag_app_name] and !release_branch_exists and git_revisions[:release] != git_revisions[stag_app_name] puts "Phase 3/3: HEADS UP. This is the last chance to detect problems." puts " The final version of "+"release/#{release_tag}".bright+" is now staged." puts puts " Test here: "+"#{app['web_url']}".bright sleep 1 @@ -261,17 +265,27 @@ 'PREVIOUS_TAG' => highest_version, 'RELEASE_TAG' => release_tag } unless 0 == finish_release(release_tag, env) abort_merge - puts "*** ERROR! Push did not complete. *** ".color(:red) + puts "*** ERROR! Could not finish release *** ".color(:red) + puts + puts "This usually means a merge conflict or" + puts "something similarly complicated has occured." + puts + puts "Please bring the universe into a state" + puts "where the above command succeeds, then try again." + puts + exit 1 end ENV['EDITOR'] = old_editor anykey when :push_to_staging - push_command = "git push #{push_url} release/#{release_tag}:master -f" - `#{push_command}` + run_each <<-EOS.strip_heredoc + :stream + git push #{push_url} release/#{release_tag}:master -f + EOS anykey when :abort_ask puts if delete_branch("release/#{release_tag}") exit 0 when :bump_tiny @@ -290,11 +304,11 @@ end end def show_pipeline_status(pipeline_name, stag_app_name, prod_app_name, release_tag, clear=true) table = TTY::Table.new header: %w{location commit tag app_last_modified app_last_modified_by dynos# state} - busy '♪♫♬ elevator music ', :pulse + busy 'loading', :classic ts = [] tpl_row = ['?', '', '', '', '', '', ''] revs = ThreadSafe::Hash.new [[0,stag_app_name],[1,prod_app_name]].each do |idx, app_name| @@ -413,38 +427,88 @@ def h @h ||= PlatformAPI.connect_oauth(Hu::API_TOKEN) end - def run_each(script) - quiet = false - failfast = true - spinner = true + def run_each(script, opts={}) + opts = { + quiet: false, + failfast: true, + spinner: true, + stream: false + }.merge(opts) + + @spinlock ||= Mutex.new # :P script.lines.each_with_index do |line, i| line.chomp! case line[0] when '#' - puts "\n" + line.bright unless quiet + puts "\n" + line.bright unless opts[:quiet] when ':' - quiet = true if line == ':quiet' - failfast = false if line == ':return' - spinner = false if line == ':nospinner' + opts[:quiet] = true if line == ':quiet' + opts[:failfast] = false if line == ':return' + opts[:spinner] = false if line == ':nospinner' + if line == ':stream' + opts[:stream] = true + opts[:quiet] = false + end end next if line.empty? or ['#', ':'].include? line[0] - busy line if spinner - output, status = Open3.capture2e(line) - unbusy if spinner - color = (status.exitstatus == 0) ? :green : :red - if status.exitstatus != 0 or !quiet - puts "\n> ".color(color) + line.color(:black).bright - puts output + + status = nil + if opts[:stream] + puts "\n> ".color(:green) + line.color(:black).bright + PTY.spawn(line) do |r,w,pid| + @tspin ||= Thread.new do + @minispin_last_char = Time.now + i = 0 + loop do + break if @minispin_last_char == :end + if 0.23 > Time.now - @minispin_last_char + sleep 0.1 + next + end + @spinlock.synchronize { + print "\e[?25l" + print Paint[' ', '#000', Lol.rainbow(1, i/3.0)] + sleep 0.12 + print 8.chr + print ' ' + print 8.chr + i += 1 + print "\e[?25h" + } + end + end + + while !r.eof? + c = r.getc + @spinlock.synchronize { + print c + @minispin_last_char = Time.now + } + end + pid, status = Process.wait2(pid) + @minispin_last_char = :end + @tspin.join + @tspin = nil + #status = PTY.check(pid) + end + else + busy line if opts[:spinner] + output, status = Open3.capture2e(line) + unbusy if opts[:spinner] + color = (status.exitstatus == 0) ? :green : :red + if status.exitstatus != 0 or !opts[:quiet] + puts "\n> ".color(color) + line.color(:black).bright + puts output + end end if status.exitstatus != 0 - shutdown if failfast - puts "Error on line #{i}: #{line}" - puts "Exit code: #{status.exitstatus}" - exit status.exitstatus if failfast + shutdown if opts[:failfast] + puts "Error, exit #{status.exitstatus}: #{line} (L#{i})".color(:red).bright + exit status.exitstatus if opts[:failfast] return status.exitstatus end end 0 end @@ -619,10 +683,11 @@ EOS end def promote_to_production run_each <<-EOS.strip_heredoc + :stream :return # Promote staging to production heroku pipelines:promote -r heroku @@ -639,10 +704,11 @@ .hu/hooks/pre_release EOS end run_each <<-EOS.strip_heredoc + :stream :return # Finish release git flow release finish #{release_tag} # Push final master (#{release_tag}) to origin @@ -677,14 +743,14 @@ def shutdown @@shutting_down = true unbusy end - def busy(msg='', format=:classic) + def busy(msg='', format=:classic, clear=true) return if @@shutting_down format ||= TTY::Formats::FORMATS.keys.sample - options = {format: format, hide_cursor: true, error_mark: "\e[31;1m✖\e[0m", success_mark: "\e[32;1m✔\e[0m", clear: true} + options = {format: format, hide_cursor: true, error_mark: "\e[31;1m✖\e[0m", success_mark: "\e[32;1m✔\e[0m", clear: clear} @@spinner = TTY::Spinner.new("\e[0;1m#{msg}#{msg.empty? ? '' : ' '}\e[0m\e[32;1m:spinner\e[0m", options) @@spinner.start end def unbusy @@ -711,10 +777,10 @@ ap *args puts "--- ^#{label}^ ---" end def safe_abort - @@spinner&.stop + @spinner&.stop printf "\e[0m\e[?25l" printf '(ヘ・_・)ヘ┳━┳' sleep 0.5 printf "\e[12D(ヘ・_・)-┳━┳" sleep 0.1