etsy-deployinator 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +368 -0
- data/Rakefile +16 -0
- data/bin/deployinator-tailer.rb +78 -0
- data/deployinator.gemspec +31 -0
- data/lib/deployinator.rb +114 -0
- data/lib/deployinator/app.rb +204 -0
- data/lib/deployinator/base.rb +58 -0
- data/lib/deployinator/config.rb +7 -0
- data/lib/deployinator/controller.rb +147 -0
- data/lib/deployinator/helpers.rb +610 -0
- data/lib/deployinator/helpers/deploy.rb +68 -0
- data/lib/deployinator/helpers/dsh.rb +42 -0
- data/lib/deployinator/helpers/git.rb +348 -0
- data/lib/deployinator/helpers/plugin.rb +50 -0
- data/lib/deployinator/helpers/stack-tail.rb +32 -0
- data/lib/deployinator/helpers/version.rb +62 -0
- data/lib/deployinator/helpers/view.rb +67 -0
- data/lib/deployinator/logging.rb +16 -0
- data/lib/deployinator/plugin.rb +7 -0
- data/lib/deployinator/stack-tail.rb +34 -0
- data/lib/deployinator/static/css/diff_style.css +283 -0
- data/lib/deployinator/static/css/highlight.css +235 -0
- data/lib/deployinator/static/css/style.css +1223 -0
- data/lib/deployinator/static/js/flot/jquery.flot.min.js +1 -0
- data/lib/deployinator/static/js/flot/jquery.flot.selection.js +299 -0
- data/lib/deployinator/static/js/jquery-1.8.3.min.js +2 -0
- data/lib/deployinator/static/js/jquery-ui-1.8.24.min.js +5 -0
- data/lib/deployinator/static/js/jquery.timed_bar.js +36 -0
- data/lib/deployinator/tasks/initialize.rake +84 -0
- data/lib/deployinator/tasks/tests.rake +22 -0
- data/lib/deployinator/templates/deploys_status.mustache +42 -0
- data/lib/deployinator/templates/generic_single_push.mustache +64 -0
- data/lib/deployinator/templates/index.mustache +12 -0
- data/lib/deployinator/templates/layout.mustache +604 -0
- data/lib/deployinator/templates/log.mustache +24 -0
- data/lib/deployinator/templates/log_table.mustache +90 -0
- data/lib/deployinator/templates/messageboxes.mustache +29 -0
- data/lib/deployinator/templates/run_logs.mustache +15 -0
- data/lib/deployinator/templates/scroll_control.mustache +8 -0
- data/lib/deployinator/templates/stream.mustache +13 -0
- data/lib/deployinator/version.rb +3 -0
- data/lib/deployinator/views/deploys_status.rb +22 -0
- data/lib/deployinator/views/index.rb +14 -0
- data/lib/deployinator/views/layout.rb +48 -0
- data/lib/deployinator/views/log.rb +12 -0
- data/lib/deployinator/views/log_table.rb +35 -0
- data/lib/deployinator/views/run_logs.rb +32 -0
- data/templates/app.rb.erb +7 -0
- data/templates/config.ru.erb +10 -0
- data/templates/helper.rb.erb +15 -0
- data/templates/stack.rb.erb +17 -0
- data/templates/template.mustache +1 -0
- data/templates/view.rb.erb +7 -0
- data/test/unit/helpers_dsh_test.rb +40 -0
- data/test/unit/helpers_test.rb +77 -0
- data/test/unit/version_test.rb +104 -0
- metadata +245 -0
@@ -0,0 +1,31 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'deployinator/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "etsy-deployinator"
|
8
|
+
gem.version = Deployinator::VERSION
|
9
|
+
gem.authors = ["JPaul"]
|
10
|
+
gem.email = ["jpaul@etsy.com"]
|
11
|
+
gem.description = %q{Deployinator as a Gem}
|
12
|
+
gem.summary = %q{Rewrite of deployinator to be a gem}
|
13
|
+
gem.homepage = ""
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
|
20
|
+
gem.add_development_dependency "mocha"
|
21
|
+
|
22
|
+
gem.add_runtime_dependency "rake"
|
23
|
+
gem.add_runtime_dependency "json"
|
24
|
+
gem.add_runtime_dependency "mustache", "~> 0.99"
|
25
|
+
gem.add_runtime_dependency "pony"
|
26
|
+
gem.add_runtime_dependency "tlsmail"
|
27
|
+
gem.add_runtime_dependency "eventmachine"
|
28
|
+
gem.add_runtime_dependency "eventmachine-tail"
|
29
|
+
gem.add_runtime_dependency "em-websocket"
|
30
|
+
gem.add_runtime_dependency "sinatra", ">=1.4.3"
|
31
|
+
end
|
data/lib/deployinator.rb
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
require 'deployinator/version'
|
2
|
+
# = Deployinator
|
3
|
+
#
|
4
|
+
# This is the main entry point for all things in the Deployination.
|
5
|
+
module Deployinator
|
6
|
+
|
7
|
+
# = Config settings
|
8
|
+
class << self
|
9
|
+
# File to log to
|
10
|
+
attr_accessor :log_file
|
11
|
+
|
12
|
+
# Your company domain name
|
13
|
+
attr_accessor :domain
|
14
|
+
|
15
|
+
# Hostname where deployinator runs
|
16
|
+
attr_accessor :hostname
|
17
|
+
|
18
|
+
# Default username for passwordless ssh
|
19
|
+
attr_accessor :default_user
|
20
|
+
|
21
|
+
# Default github_host
|
22
|
+
attr_accessor :github_host
|
23
|
+
|
24
|
+
# Bug or issue tracker - proc that takes the issue id as an argument
|
25
|
+
# ex: Deployinator.issue_tracker = proc {|issue| "http://foo/browse/#{issue}"}
|
26
|
+
attr_accessor :issue_tracker
|
27
|
+
|
28
|
+
# a hash for context specifics settings (test,dev,production) of deployinator itself
|
29
|
+
attr_accessor :app_context
|
30
|
+
|
31
|
+
# Your install root
|
32
|
+
attr_accessor :root_dir
|
33
|
+
|
34
|
+
# Git info per stack
|
35
|
+
attr_accessor :git_info_for_stack
|
36
|
+
|
37
|
+
# Deploy Host
|
38
|
+
attr_accessor :deploy_host
|
39
|
+
|
40
|
+
# Timing Log path
|
41
|
+
attr_accessor :timing_log_path
|
42
|
+
|
43
|
+
# Log path
|
44
|
+
attr_accessor :log_path
|
45
|
+
|
46
|
+
attr_accessor :git_sha_length
|
47
|
+
|
48
|
+
attr_accessor :global_plugins
|
49
|
+
|
50
|
+
attr_accessor :stack_plugins
|
51
|
+
|
52
|
+
attr_accessor :stack_tailer_port
|
53
|
+
|
54
|
+
attr_accessor :admin_groups
|
55
|
+
@admin_groups = []
|
56
|
+
|
57
|
+
# the controller class. defaults to Deployinator::Controller
|
58
|
+
# if you override this it should be a subclass of Deployinator::Controller
|
59
|
+
attr_accessor :deploy_controller
|
60
|
+
|
61
|
+
def initialize
|
62
|
+
@stack_plugins = {}
|
63
|
+
@global_plugins = []
|
64
|
+
@admin_groups = []
|
65
|
+
end
|
66
|
+
|
67
|
+
# Base root path
|
68
|
+
# Takes an optional argument of a string or array and returns the path(s)
|
69
|
+
# From the root of deployinator
|
70
|
+
def root(path = nil)
|
71
|
+
base = Deployinator.root_dir
|
72
|
+
path ? File.join(base, path) : base
|
73
|
+
end
|
74
|
+
|
75
|
+
# is a log file defined?
|
76
|
+
def log_file?
|
77
|
+
log_file
|
78
|
+
end
|
79
|
+
|
80
|
+
# Running environment for deployinator
|
81
|
+
# This is taken from RACK_ENV or RAILS_ENV
|
82
|
+
# *note* this is different from deployinator's concept of stacks/environments
|
83
|
+
def env
|
84
|
+
ENV["RACK_ENV"] || ENV["RAILS_ENV"] || "development"
|
85
|
+
end
|
86
|
+
|
87
|
+
# Gets all the stack files in the stack directory
|
88
|
+
def get_stack_files
|
89
|
+
Dir[Deployinator.root(["stacks", "*.rb"])]
|
90
|
+
end
|
91
|
+
|
92
|
+
# Gets all the stack names without the .rb extension
|
93
|
+
def get_stacks
|
94
|
+
self.get_stack_files.sort.map do |file|
|
95
|
+
File.basename(file, ".rb")
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
Deployinator.root_dir = Dir.pwd
|
102
|
+
Deployinator.app_context = {}
|
103
|
+
Deployinator.admin_groups = []
|
104
|
+
Deployinator.global_plugins = []
|
105
|
+
Deployinator.log_file = Deployinator.root(["log", "development.log"])
|
106
|
+
Deployinator.log_path = Deployinator.root(["log", "deployinator.log"])
|
107
|
+
Deployinator.timing_log_path = Deployinator.root(["log", "deployinator-timing.log"])
|
108
|
+
Deployinator.git_sha_length = "10"
|
109
|
+
Deployinator.default_user = `whoami`
|
110
|
+
Deployinator.stack_tailer_port = 7778
|
111
|
+
Deployinator.github_host = 'github.com'
|
112
|
+
Deployinator.app_context['context'] = 'dev'
|
113
|
+
|
114
|
+
|
@@ -0,0 +1,204 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
require 'mustache/sinatra'
|
3
|
+
require 'deployinator'
|
4
|
+
require 'deployinator/controller'
|
5
|
+
require 'deployinator/helpers'
|
6
|
+
require 'deployinator/helpers/deploy'
|
7
|
+
require 'deployinator/helpers/version'
|
8
|
+
require 'deployinator/helpers/git'
|
9
|
+
require 'deployinator/helpers/plugin'
|
10
|
+
require 'deployinator/views/index'
|
11
|
+
require 'deployinator/views/log'
|
12
|
+
require 'deployinator/views/run_logs'
|
13
|
+
require 'deployinator/views/log_table'
|
14
|
+
require 'deployinator/views/deploys_status'
|
15
|
+
|
16
|
+
module Deployinator
|
17
|
+
class DeployinatorApp < Sinatra::Base
|
18
|
+
register Mustache::Sinatra
|
19
|
+
helpers Deployinator::Helpers,
|
20
|
+
Deployinator::Helpers::DeployHelpers,
|
21
|
+
Deployinator::Helpers::GitHelpers,
|
22
|
+
Deployinator::Helpers::VersionHelpers,
|
23
|
+
Deployinator::Helpers::PluginHelpers
|
24
|
+
|
25
|
+
def github_diff_url(params)
|
26
|
+
stack = params[:stack].intern
|
27
|
+
gh_info = git_info_for_stack[stack]
|
28
|
+
"https://#{which_github_host(stack)}/#{gh_info[:user]}/#{gh_info[:repository]}/compare/#{params[:r1]}...#{params[:r2]}"
|
29
|
+
end
|
30
|
+
|
31
|
+
set :mustache, {
|
32
|
+
:views => Deployinator.root('views'),
|
33
|
+
:templates => Deployinator.root('templates'),
|
34
|
+
:namespace => Deployinator::Views
|
35
|
+
}
|
36
|
+
|
37
|
+
set :public_folder, Deployinator.root('public')
|
38
|
+
set :static, true
|
39
|
+
|
40
|
+
before do
|
41
|
+
register_plugins(nil)
|
42
|
+
init(env)
|
43
|
+
@disabled_override = params[:override].nil? ? false : true
|
44
|
+
end
|
45
|
+
|
46
|
+
get '/' do
|
47
|
+
mustache Deployinator::Views::Index
|
48
|
+
end
|
49
|
+
|
50
|
+
get '/run_logs/view/:log' do
|
51
|
+
template = open("#{File.dirname(__FILE__)}/templates/stream.mustache").read
|
52
|
+
template.gsub!("{{ yield }}", "{{{yield}}}")
|
53
|
+
Mustache.render(template, :yield => open("run_logs/" + params[:log]).read)
|
54
|
+
end
|
55
|
+
|
56
|
+
get '/run_logs/?' do
|
57
|
+
@stack = "log"
|
58
|
+
@params = params
|
59
|
+
mustache Deployinator::Views::RunLogs
|
60
|
+
end
|
61
|
+
|
62
|
+
get '/run_logs/latest/:log_type' do
|
63
|
+
run_logs = get_run_logs(:limit => 1, :type => params[:log_type])
|
64
|
+
if run_logs.count == 1
|
65
|
+
run_log = run_logs.first[:name]
|
66
|
+
redirect "/run_logs/view/#{run_log}"
|
67
|
+
else
|
68
|
+
redirect "/"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
get '/log/?' do
|
73
|
+
@stack = "log"
|
74
|
+
@params = params
|
75
|
+
mustache Deployinator::Views::LogTable
|
76
|
+
end
|
77
|
+
|
78
|
+
get '/:stack/can-deploy' do
|
79
|
+
lock_info = push_lock_info(params["stack"]) || {}
|
80
|
+
lock_info[:can_deploy] = lock_info.empty?
|
81
|
+
content_type "application/json"
|
82
|
+
lock_info.to_json
|
83
|
+
end
|
84
|
+
|
85
|
+
get '/diff/:stack/:r1/:r2/?' do
|
86
|
+
@stack = params[:stack]
|
87
|
+
diff(params["r1"], params["r2"], params["stack"], params[:time])
|
88
|
+
end
|
89
|
+
|
90
|
+
get '/diff/:stack/:r1/:r2/github/?' do
|
91
|
+
redirect github_diff_url(params)
|
92
|
+
end
|
93
|
+
|
94
|
+
get '/head_rev/:stack' do
|
95
|
+
git_head_rev(params[:stack]).chomp
|
96
|
+
end
|
97
|
+
|
98
|
+
get '/:thing' do
|
99
|
+
@stack = params[:thing]
|
100
|
+
@params = params
|
101
|
+
register_plugins(@stack)
|
102
|
+
begin
|
103
|
+
mustache @stack
|
104
|
+
rescue Errno::ENOENT
|
105
|
+
pass
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
get '/:stack/remove-lock' do
|
110
|
+
stack = params[:stack]
|
111
|
+
unlock_pushes(stack) if can_remove_stack_lock?
|
112
|
+
redirect "/#{stack}"
|
113
|
+
end
|
114
|
+
|
115
|
+
# return a list of all deploys as JSON
|
116
|
+
get '/deploys/?' do
|
117
|
+
get_list_of_deploys.to_json
|
118
|
+
end
|
119
|
+
|
120
|
+
get '/static/css/style.css?:version' do
|
121
|
+
send_file "#{File.dirname(__FILE__)}/static/css/style.css"
|
122
|
+
end
|
123
|
+
|
124
|
+
get '/static/css/diff_style.css' do
|
125
|
+
send_file "#{File.dirname(__FILE__)}/static/css/diff_style.css"
|
126
|
+
end
|
127
|
+
|
128
|
+
get '/static/css/highlight.css' do
|
129
|
+
send_file "#{File.dirname(__FILE__)}/static/css/highlight.css"
|
130
|
+
end
|
131
|
+
|
132
|
+
get '/js/flot/jquery.flot.min.js' do
|
133
|
+
send_file "#{File.dirname(__FILE__)}/static/js/flot/jquery.flot.min.js"
|
134
|
+
end
|
135
|
+
|
136
|
+
get '/js/flot/jquery.flot.selection.js' do
|
137
|
+
send_file "#{File.dirname(__FILE__)}/static/js/flot/jquery.flot.selection.js"
|
138
|
+
end
|
139
|
+
|
140
|
+
get '/js/jquery-1.8.3.min.js' do
|
141
|
+
send_file "#{File.dirname(__FILE__)}/static/js/jquery-1.8.3.min.js"
|
142
|
+
end
|
143
|
+
|
144
|
+
get '/js/jquery-ui-1.8.24.min.js' do
|
145
|
+
send_file "#{File.dirname(__FILE__)}/static/js/jquery-ui-1.8.24.min.js"
|
146
|
+
end
|
147
|
+
|
148
|
+
get '/js/jquery.timed_bar.js' do
|
149
|
+
send_file "#{File.dirname(__FILE__)}/static/js/jquery.timed_bar.js"
|
150
|
+
end
|
151
|
+
|
152
|
+
get '/deploys_status' do
|
153
|
+
mustache Deployinator::Views::DeploysStatus
|
154
|
+
end
|
155
|
+
|
156
|
+
get '/log.txt' do
|
157
|
+
content_type :text
|
158
|
+
`tac #{Deployinator.log_path}#{ " | head -n #{params[:limit]}" if params[:limit]}`
|
159
|
+
end
|
160
|
+
|
161
|
+
get '/timing_log.txt' do
|
162
|
+
content_type :text
|
163
|
+
`tac #{Deployinator.timing_log_path}`
|
164
|
+
end
|
165
|
+
|
166
|
+
get '/ti/:stack/:env' do
|
167
|
+
@stack = params[:stack]
|
168
|
+
average_duration(params["env"], params["stack"]).to_s
|
169
|
+
end
|
170
|
+
|
171
|
+
# this is the API endpoint to asynchronously start a deploy that runs in
|
172
|
+
# the background.
|
173
|
+
post '/deploys/?' do
|
174
|
+
params[:username] = @username
|
175
|
+
params[:block] = Proc.new { |line| foo = line }
|
176
|
+
deploy_running = is_deploy_active?(params[:stack], params[:stage])
|
177
|
+
|
178
|
+
# if this deploy is already running, return 403
|
179
|
+
if deploy_running
|
180
|
+
return 403
|
181
|
+
end
|
182
|
+
|
183
|
+
fork {
|
184
|
+
Signal.trap("HUP") { exit }
|
185
|
+
Deployinator.setup_logging
|
186
|
+
$0 = get_deploy_process_title(params[:stack], params[:stage])
|
187
|
+
controller = Deployinator.deploy_controller || Deployinator::Controller
|
188
|
+
d = controller.new
|
189
|
+
d.run(params)
|
190
|
+
}
|
191
|
+
200
|
192
|
+
end
|
193
|
+
|
194
|
+
delete '/deploys/?' do
|
195
|
+
return 400 if (params[:stack].nil? || params[:stage].nil?)
|
196
|
+
res = stop_deploy(params[:stack], params[:stage])
|
197
|
+
unless res
|
198
|
+
return 404
|
199
|
+
end
|
200
|
+
|
201
|
+
200
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "bundler"
|
3
|
+
Bundler.setup
|
4
|
+
|
5
|
+
require 'deployinator'
|
6
|
+
|
7
|
+
$LOAD_PATH.unshift Deployinator.root unless $LOAD_PATH.include? Deployinator.root
|
8
|
+
$LOAD_PATH.unshift Deployinator.root("lib") unless $LOAD_PATH.include? Deployinator.root("lib")
|
9
|
+
|
10
|
+
require 'deployinator/config'
|
11
|
+
|
12
|
+
require "socket"
|
13
|
+
require 'pony'
|
14
|
+
|
15
|
+
require 'sinatra/base'
|
16
|
+
require "mustache/sinatra"
|
17
|
+
|
18
|
+
# Silence mustache warnings
|
19
|
+
module Mustache::Sinatra::Helpers
|
20
|
+
def warn(msg); nil; end
|
21
|
+
end
|
22
|
+
|
23
|
+
# ruby Std lib
|
24
|
+
require 'open3'
|
25
|
+
require 'benchmark'
|
26
|
+
require 'net/http'
|
27
|
+
require 'open-uri'
|
28
|
+
require 'uri'
|
29
|
+
require 'time'
|
30
|
+
require 'json'
|
31
|
+
require 'resolv'
|
32
|
+
|
33
|
+
require "deployinator/helpers"
|
34
|
+
require "deployinator/views/layout"
|
35
|
+
require "deployinator/helpers/view"
|
36
|
+
require "deployinator/app"
|
37
|
+
|
38
|
+
class Mustache
|
39
|
+
include Deployinator::Helpers,
|
40
|
+
Deployinator::Helpers::ViewHelpers
|
41
|
+
end
|
42
|
+
|
43
|
+
# Ruby 1.8.6 is teh LAMEZ0Rz
|
44
|
+
unless Symbol.respond_to?(:to_proc)
|
45
|
+
class Symbol
|
46
|
+
def to_proc
|
47
|
+
Proc.new { |obj, *args| obj.send(self, *args) }
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
unless String.respond_to?(:start_with?)
|
53
|
+
class String
|
54
|
+
def start_with?(str)
|
55
|
+
self.index(str) == 0
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,147 @@
|
|
1
|
+
require 'deployinator'
|
2
|
+
require 'deployinator/helpers'
|
3
|
+
require 'deployinator/helpers/version'
|
4
|
+
require "deployinator/helpers/plugin"
|
5
|
+
|
6
|
+
module Deployinator
|
7
|
+
|
8
|
+
# Public: this class represents the Deploy object with all the properties
|
9
|
+
# the different helper and stack methods need to do the deploy. It is
|
10
|
+
# basically an almost empty class and gets all of its functionality by the
|
11
|
+
# modules it includes/extends based on the stack we are deploying.
|
12
|
+
class Deploy
|
13
|
+
include Deployinator::Helpers,
|
14
|
+
Deployinator::Helpers::VersionHelpers,
|
15
|
+
Deployinator::Helpers::PluginHelpers
|
16
|
+
|
17
|
+
# Public: initialize the deploy class with instance variables that are
|
18
|
+
# needed by the deploy methods, runlog helpers and all that
|
19
|
+
#
|
20
|
+
# Params:
|
21
|
+
# args - hash which at least has the following fields:
|
22
|
+
# { :username => "name of the person that is deploying",
|
23
|
+
# :stack => "the name of the stack to deploy",
|
24
|
+
# :stage => "stage of the stack to deploy"
|
25
|
+
# }
|
26
|
+
#
|
27
|
+
# Returns the runlog filename
|
28
|
+
def initialize(args)
|
29
|
+
@deploy_start_time = Time.now.to_i
|
30
|
+
@start_time = Time.now.to_i
|
31
|
+
@username = args[:username]
|
32
|
+
@host = `hostname -s`
|
33
|
+
@stack = args[:stack]
|
34
|
+
@method = args[:method]
|
35
|
+
@filename = "#{@deploy_start_time}-#{@username}-#{args[:method]}.html"
|
36
|
+
@deploy_time = Time.now.to_i
|
37
|
+
|
38
|
+
# This gets the runlog output on the console; is used by log_and_stream
|
39
|
+
@block = args[:block] || Proc.new do |output|
|
40
|
+
$stdout.write output.gsub!(/(<[^>]*>)|\n|\t/s) {" "}
|
41
|
+
$stdout.write "\n"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def get_filename
|
46
|
+
@filename
|
47
|
+
end
|
48
|
+
|
49
|
+
def get_deploy_time
|
50
|
+
@deploy_time
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Public: the main Controller class knows how to extract options from the
|
55
|
+
# options argument it gets passed from its run method and then prepares the
|
56
|
+
# Deploy class to be ready to deploy.
|
57
|
+
class Controller
|
58
|
+
|
59
|
+
# Public: get the correct method name for the stage to deploy. This allows us to
|
60
|
+
# call things princess and prod even though the methods in the stacks have crazy
|
61
|
+
# names.
|
62
|
+
#
|
63
|
+
# Params:
|
64
|
+
# stack - the name of the stack to deploy
|
65
|
+
# stage - the stage of the stack to deploy
|
66
|
+
#
|
67
|
+
# Returns the name of the deploy method as a String which then can be sent
|
68
|
+
# to the Deploy class
|
69
|
+
def stage_to_method(stack, stage)
|
70
|
+
"#{stack}_#{stage}"
|
71
|
+
end
|
72
|
+
|
73
|
+
# Public: run the actual deploy from the given parameters
|
74
|
+
#
|
75
|
+
# Params:
|
76
|
+
# options - hash that includes at least the following fields:
|
77
|
+
# { :username => "name of the user that is deploying",
|
78
|
+
# :stack => "name of the stack to deploy",
|
79
|
+
# :stage => "name of the stage of the stack to deploy"
|
80
|
+
# }
|
81
|
+
#
|
82
|
+
# Returns nothing
|
83
|
+
def run(options)
|
84
|
+
options[:method] = stage_to_method(options[:stack], options[:stage])
|
85
|
+
if options[:method].nil?
|
86
|
+
raise "No method defined for me to call: #{options[:stack]}, #{options[:stage]}"
|
87
|
+
end
|
88
|
+
|
89
|
+
# config pus needs :env populated here
|
90
|
+
options[:env] = {
|
91
|
+
:username => options[:username]
|
92
|
+
}
|
93
|
+
|
94
|
+
if Deployinator.get_stacks.include?(options[:stack])
|
95
|
+
require "stacks/#{options[:stack]}"
|
96
|
+
klass = "#{Mustache.classify(options[:stack])}Deploy"
|
97
|
+
deploy_class = Deployinator::Stacks.const_get("#{klass}")
|
98
|
+
else
|
99
|
+
raise "No such stack #{options[:stack]}"
|
100
|
+
end
|
101
|
+
|
102
|
+
deploy_instance = deploy_class.new(options)
|
103
|
+
deploy_instance.register_plugins(options[:stack])
|
104
|
+
|
105
|
+
deploy_instance.lock_pushes(options[:stack], options[:username], options[:method])
|
106
|
+
|
107
|
+
@start_time = Time.now
|
108
|
+
deploy_instance.log_and_stream "Push started at #{@start_time.to_i}\n"
|
109
|
+
deploy_instance.log_and_stream "Calling #{options[:method]}\n";
|
110
|
+
deploy_instance.link_stack_logfile(deploy_instance.get_filename, options[:stack])
|
111
|
+
|
112
|
+
deploy_instance.raise_event(:deploy_start)
|
113
|
+
|
114
|
+
begin
|
115
|
+
state = deploy_instance.send(options[:method], options)
|
116
|
+
rescue Exception => e
|
117
|
+
deploy_instance.log_error("There was an exception during this deploy. Aborted!", e)
|
118
|
+
deploy_instance.raise_event(:deploy_error)
|
119
|
+
end
|
120
|
+
|
121
|
+
if state.nil? || !state.is_a?(Hash)
|
122
|
+
state = {}
|
123
|
+
end
|
124
|
+
deploy_instance.raise_event(:deploy_end, state)
|
125
|
+
|
126
|
+
if options[:method].match(/config_push/)
|
127
|
+
env = options[:method].match(/prod/) ? "production" : "princess"
|
128
|
+
elsif options[:method].match(/force_builda/)
|
129
|
+
env = "force asset rebuild"
|
130
|
+
else
|
131
|
+
env = options[:method][/(dev|qa|production|princess|prod|webs|stage|config)/i, 1] || "other"
|
132
|
+
env = "production" if env.match(/prod|webs/)
|
133
|
+
end
|
134
|
+
|
135
|
+
# display a message that the deploy is done and call the JavaScript
|
136
|
+
# deploy done function
|
137
|
+
msg = "<h4>#{env.to_s.upcase} deploy in #{options[:stack]} stack complete</h4>"
|
138
|
+
deploy_instance.log_and_stream(msg+"<p class='output'>")
|
139
|
+
deploy_instance.log_and_stream("<script id='deploy-done'>window.deploy_done('#{msg}', '#{options[:stage]}');</script>")
|
140
|
+
|
141
|
+
deploy_instance.unlock_pushes(options[:stack])
|
142
|
+
deploy_instance.move_stack_logfile(options[:stack])
|
143
|
+
|
144
|
+
return deploy_instance
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|