blend 0.1.4
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/Rakefile +38 -0
- data/bin/blend +34 -0
- data/lib/blend.rb +28 -0
- data/lib/blend/chatbot/bot.rb +352 -0
- data/lib/blend/cli.rb +38 -0
- data/lib/blend/cli/github.rb +140 -0
- data/lib/blend/cli/heroku.rb +232 -0
- data/lib/blend/cli/hipchat.rb +61 -0
- data/lib/blend/cli/juice.rb +493 -0
- data/lib/blend/client.rb +63 -0
- data/lib/blend/client/github_client.rb +106 -0
- data/lib/blend/client/heroku_client.rb +87 -0
- data/lib/blend/client/hipchat_client.rb +78 -0
- data/lib/blend/client/juice_client.rb +400 -0
- data/lib/blend/core_ext/fixnum.rb +5 -0
- data/lib/blend/core_ext/object.rb +13 -0
- data/lib/blend/core_ext/string.rb +9 -0
- data/lib/blend/exceptions.rb +16 -0
- data/lib/blend/status/domain.rb +225 -0
- data/lib/blend/status/environment.rb +167 -0
- data/lib/blend/status/project.rb +227 -0
- data/lib/blend/status/project_resolver.rb +183 -0
- data/lib/blend/status/repo.rb +51 -0
- data/lib/blend/status/team.rb +29 -0
- data/lib/blend/version.rb +10 -0
- metadata +225 -0
@@ -0,0 +1,16 @@
|
|
1
|
+
module Blend
|
2
|
+
module Exceptions
|
3
|
+
class AuthenticationFailure < StandardError; end
|
4
|
+
class LoginAuthenticationFailure < StandardError; end
|
5
|
+
class AlreadyLoggedIn < StandardError; end
|
6
|
+
class AlreadyLoggedOut < StandardError; end
|
7
|
+
class HipchatAuthenticationFailure < StandardError; end
|
8
|
+
|
9
|
+
class << self
|
10
|
+
def formatted(e)
|
11
|
+
puts "#{e.backtrace.shift}: #{e.message}"
|
12
|
+
puts e.backtrace.first(10).map{|x| "\t"+x}.join("\n")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,225 @@
|
|
1
|
+
require 'dnsruby'
|
2
|
+
require 'whois'
|
3
|
+
require 'httpclient'
|
4
|
+
|
5
|
+
module Blend
|
6
|
+
module Status
|
7
|
+
class Domain
|
8
|
+
attr_accessor :project, :domain, :res, :environment
|
9
|
+
|
10
|
+
def initialize( project, environment, domain )
|
11
|
+
@project = project
|
12
|
+
@environment = environment
|
13
|
+
@domain = domain
|
14
|
+
@res = Dnsruby::Resolver.new
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
class << self
|
19
|
+
def check(domain)
|
20
|
+
dc = self.new(domain)
|
21
|
+
|
22
|
+
result = {}
|
23
|
+
begin
|
24
|
+
|
25
|
+
result[:registered] = dc.registered?
|
26
|
+
result[:registrar] = dc.registrar
|
27
|
+
result[:ssl] = dc.ssl
|
28
|
+
result[:expires] = dc.expires
|
29
|
+
result[:owner] = dc.owner
|
30
|
+
result[:name_servers] = dc.name_servers
|
31
|
+
result[:dns] = {
|
32
|
+
ns: dc.ns,
|
33
|
+
mx: dc.mx,
|
34
|
+
cname: dc.cname,
|
35
|
+
a: dc.a
|
36
|
+
}
|
37
|
+
|
38
|
+
rescue Dnsruby::ServFail => e
|
39
|
+
result[:error] = "DomainChecker encountered #{e.to_s}: You might just need to retry this."
|
40
|
+
end
|
41
|
+
|
42
|
+
result
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
## Find out meta data
|
48
|
+
|
49
|
+
def registered?
|
50
|
+
whois.registered?
|
51
|
+
end
|
52
|
+
|
53
|
+
def registrar
|
54
|
+
whois.registrar
|
55
|
+
end
|
56
|
+
|
57
|
+
def owner
|
58
|
+
whois.registrant_contacts
|
59
|
+
end
|
60
|
+
|
61
|
+
def expires
|
62
|
+
whois.expires_on
|
63
|
+
end
|
64
|
+
|
65
|
+
def inbound_mailers
|
66
|
+
get_data(mx).sort { |a,b| a[0] <=> b[0]}
|
67
|
+
end
|
68
|
+
|
69
|
+
def name_servers
|
70
|
+
get_data(ns)
|
71
|
+
end
|
72
|
+
|
73
|
+
def ssl
|
74
|
+
if @ssl.nil?
|
75
|
+
c = HTTPClient.new
|
76
|
+
c.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
77
|
+
p = c.get( "https://#{domain}")
|
78
|
+
@ssl = p.peer_cert
|
79
|
+
end
|
80
|
+
return nil if( ssl_common_name.nil? )
|
81
|
+
@ssl
|
82
|
+
end
|
83
|
+
|
84
|
+
def ssl_exists?
|
85
|
+
!ssl.nil?
|
86
|
+
end
|
87
|
+
|
88
|
+
def ssl_valid_until
|
89
|
+
return nil if ssl.nil?
|
90
|
+
ssl.not_after
|
91
|
+
end
|
92
|
+
|
93
|
+
def ssl_common_name
|
94
|
+
ssl if @ssl.nil?
|
95
|
+
return nil if @ssl.nil?
|
96
|
+
ret = (@ssl.subject.to_a.select { |x| x[0] == 'CN' }.first || [])[1]
|
97
|
+
return nil if ( ret =~ /herokuapp/ )
|
98
|
+
ret
|
99
|
+
end
|
100
|
+
|
101
|
+
## Details
|
102
|
+
|
103
|
+
def lookup( type )
|
104
|
+
@results ||= {}
|
105
|
+
if @results[type].nil?
|
106
|
+
@results[type] = parse_answer( type )
|
107
|
+
if type == "A" || type == "CNAME"
|
108
|
+
@results[type] = parse_answer type, @results[type][:domains]
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# @results[type]
|
113
|
+
# @results = { domain: @domain }
|
114
|
+
# @results[:ns] = parse_answer( "NS" )
|
115
|
+
# @results[:a] = parse_answer( "A" )
|
116
|
+
# @results[:a] = parse_answer( "A", @results[:a][:domains] )
|
117
|
+
# @results[:cname] = parse_answer( "CNAME" )
|
118
|
+
# @results[:cname] = parse_answer( "CNAME", @results[:cname][:domains] )
|
119
|
+
# @results[:mx] = parse_answer( "MX" )
|
120
|
+
# end
|
121
|
+
@results[type]
|
122
|
+
end
|
123
|
+
|
124
|
+
def ns
|
125
|
+
lookup "NS"
|
126
|
+
end
|
127
|
+
|
128
|
+
def a
|
129
|
+
lookup "A"
|
130
|
+
end
|
131
|
+
|
132
|
+
def mx
|
133
|
+
lookup "MX"
|
134
|
+
end
|
135
|
+
|
136
|
+
def cname
|
137
|
+
lookup "CNAME"
|
138
|
+
end
|
139
|
+
|
140
|
+
def whois
|
141
|
+
@whois ||= Whois.lookup @domain
|
142
|
+
end
|
143
|
+
|
144
|
+
def parse_answer( type, domains = false )
|
145
|
+
domain = @domain
|
146
|
+
domain = "www.#{@domain}" if domains
|
147
|
+
ret = {domains: []}
|
148
|
+
ret = {domains: domains} if domains
|
149
|
+
begin
|
150
|
+
rr = @res.query( domain, type)
|
151
|
+
# puts rr.answer
|
152
|
+
rr.answer.each do |answer|
|
153
|
+
ret[:domains] << { domain: domain, name:answer.name.to_s, ttl: answer.ttl, data: answer.rdata, type: answer.type } if answer.type == type
|
154
|
+
end
|
155
|
+
rescue Dnsruby::ResolvTimeout
|
156
|
+
ret[:error] = :timeout
|
157
|
+
rescue Dnsruby::NXDomain
|
158
|
+
ret[:error] = :notfound
|
159
|
+
end
|
160
|
+
|
161
|
+
ret
|
162
|
+
end
|
163
|
+
|
164
|
+
def get_data array
|
165
|
+
array[:domains].collect{ |x| x[:data] }
|
166
|
+
end
|
167
|
+
|
168
|
+
# def registrar
|
169
|
+
# last_2_records ns
|
170
|
+
# end
|
171
|
+
|
172
|
+
# def mailer
|
173
|
+
# records( mx ).collect { |x| x[1].labels[-2..-1].collect { |x| x.to_s.downcase }.join( "." ) }.uniq.select { |x| x != "google.com"}
|
174
|
+
# end
|
175
|
+
|
176
|
+
# def last_2_records a
|
177
|
+
# records( a ).collect { |x| x.labels[-2..-1].collect { |x| x.to_s }.join( "." ) }.uniq
|
178
|
+
# end
|
179
|
+
|
180
|
+
# def records v
|
181
|
+
# if v[:domains]
|
182
|
+
# v[:domains].collect { |x| x[:data] }
|
183
|
+
# else
|
184
|
+
# []
|
185
|
+
# end
|
186
|
+
# end
|
187
|
+
|
188
|
+
def heroku?
|
189
|
+
a_ips = a[:domains].select { |x| x[:domain] == @domain }.collect { |x| x[:data].to_s }.sort
|
190
|
+
# puts a_ips
|
191
|
+
return true if a_ips == ["174.129.212.2", "75.101.145.87", "75.101.163.44"]
|
192
|
+
|
193
|
+
|
194
|
+
# puts cname[:domains].to_s
|
195
|
+
# return false if cname[:domains].first[:data].to_s != "proxy.heroku.com"
|
196
|
+
|
197
|
+
return true
|
198
|
+
end
|
199
|
+
|
200
|
+
def check key, method
|
201
|
+
ret = __send__( method )
|
202
|
+
ret = false if ret.nil?
|
203
|
+
ret = false if ret == []
|
204
|
+
ret = ret.collect { |x| x[:name] || x['name'] }.join( "," ) if ret.is_a? Array
|
205
|
+
|
206
|
+
pass = ret
|
207
|
+
|
208
|
+
if( ret.is_a? Integer )
|
209
|
+
if( method == :dyno_redundancy)
|
210
|
+
pass = ret > 1
|
211
|
+
ret = "#{ret} dynos"
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
printf "%20s: ", key
|
216
|
+
if( pass )
|
217
|
+
printf "\u2713 #{ret}\n".encode('utf-8').green
|
218
|
+
else
|
219
|
+
printf "\u2718 #{ret}\n".encode('utf-8').red
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
@@ -0,0 +1,167 @@
|
|
1
|
+
module Blend
|
2
|
+
module Status
|
3
|
+
class Environment
|
4
|
+
attr_accessor :project, :server, :environment
|
5
|
+
|
6
|
+
def initialize( project, server, environment )
|
7
|
+
@project = project
|
8
|
+
@server = server
|
9
|
+
@environment = environment
|
10
|
+
end
|
11
|
+
|
12
|
+
def check key, method
|
13
|
+
ret = __send__( method )
|
14
|
+
ret = false if ret.nil?
|
15
|
+
ret = false if ret == []
|
16
|
+
ret = ret.collect do |x|
|
17
|
+
if( x.is_a? Hash )
|
18
|
+
x[:name] || x['name']
|
19
|
+
else
|
20
|
+
x
|
21
|
+
end
|
22
|
+
end.join( "," ) if ret.is_a? Array
|
23
|
+
|
24
|
+
pass = ret
|
25
|
+
|
26
|
+
if( ret.is_a? Integer )
|
27
|
+
if( method == :dyno_redundancy)
|
28
|
+
pass = ret > 1
|
29
|
+
ret = "#{ret} dynos"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
printf "%20s: ", key
|
34
|
+
if( pass )
|
35
|
+
printf "\u2713 #{ret}\n".encode('utf-8').green
|
36
|
+
else
|
37
|
+
printf "\u2718 #{ret}\n".encode('utf-8').red
|
38
|
+
if( @project.resolve )
|
39
|
+
r = "resolve_#{method}".to_sym
|
40
|
+
__send__(r) if respond_to? r
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def client
|
47
|
+
Blend::Client.heroku_client
|
48
|
+
end
|
49
|
+
|
50
|
+
def log_monitoring
|
51
|
+
client.addons(@server, /(logentries|keen|papertrail|loggly|flydata)/)
|
52
|
+
end
|
53
|
+
|
54
|
+
def app_monitoring
|
55
|
+
client.addons(@server, /(relic)/)
|
56
|
+
end
|
57
|
+
|
58
|
+
def exception_handling
|
59
|
+
client.addons(@server, /(airbrake|exceptional)/)
|
60
|
+
end
|
61
|
+
|
62
|
+
def deployhooks
|
63
|
+
client.addons(@server, /deployhooks/)
|
64
|
+
end
|
65
|
+
|
66
|
+
def resolve_deployhooks
|
67
|
+
system( "echo heroku addons:add deployhooks:hipchat --auth_token=#{@project.juice_client.hipchat_api} --room=\"#{@project.config['hipchat_room']}\" --app #{@server}")
|
68
|
+
system( "heroku addons:add deployhooks:hipchat --auth_token=#{@project.juice_client.hipchat_api} --room=\"#{@project.config['hipchat_room']}\" --app #{@server}" )
|
69
|
+
Blend::Client::hipchat_client.post_message @project.config['hipchat_room'], "Heroku app: #{@server} commit hook now added"
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
def ssl
|
74
|
+
client.addons(@server, /ssl/)
|
75
|
+
end
|
76
|
+
|
77
|
+
def backups
|
78
|
+
client.backups(@server).collect { |x| x[:plan] }
|
79
|
+
end
|
80
|
+
|
81
|
+
def database
|
82
|
+
client.databases(@server).collect { |x| x[:plan] }
|
83
|
+
end
|
84
|
+
|
85
|
+
def dyno_redundancy
|
86
|
+
client.dynos(@server).to_i
|
87
|
+
end
|
88
|
+
|
89
|
+
def stack
|
90
|
+
client.stack( @server ) == 'cedar'
|
91
|
+
end
|
92
|
+
|
93
|
+
def domains
|
94
|
+
client.nonheroku_domains( @server )
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
__END__
|
100
|
+
|
101
|
+
|
102
|
+
|
103
|
+
|
104
|
+
|
105
|
+
desc 'check_domains [APP]', 'Check domains'
|
106
|
+
def check_domains(app)
|
107
|
+
client.nonheroku_domains(app).each do |domain|
|
108
|
+
puts "\nChecking domain #{domain}:".blue
|
109
|
+
result = DomainChecker.check(domain)
|
110
|
+
|
111
|
+
if result.include? :error
|
112
|
+
puts result[:error].red
|
113
|
+
return
|
114
|
+
end
|
115
|
+
|
116
|
+
# Check registration
|
117
|
+
if result[:registered]
|
118
|
+
r = result[:registrar]
|
119
|
+
|
120
|
+
# Registrar:
|
121
|
+
if r.nil?
|
122
|
+
printf "%25s: %s", 'Registrar', format_result(:warn, "DNS not configured correctly for #{domain}")
|
123
|
+
else
|
124
|
+
registrar = [r['name'], r['organization'], r['url']].reject(&:nil?).join('; ')
|
125
|
+
printf "%25s: %s", 'Registrar', format_result(:pass, registrar)
|
126
|
+
end
|
127
|
+
else
|
128
|
+
printf "%25s: %s", 'Registrar', format_result(:fail)
|
129
|
+
end
|
130
|
+
|
131
|
+
|
132
|
+
unless result[:expires].nil?
|
133
|
+
# Expiration:
|
134
|
+
days_to_expiration = ((result[:expires] - Time.now)/(3600.0*24.0)).to_i
|
135
|
+
formatted_dte = "#{result[:expires].strftime("%F")} (#{days_to_expiration} days from now)"
|
136
|
+
if days_to_expiration < 30
|
137
|
+
state = :fail
|
138
|
+
elsif days_to_expiration < 30*3
|
139
|
+
state = :warn
|
140
|
+
else
|
141
|
+
state = :pass
|
142
|
+
end
|
143
|
+
|
144
|
+
printf "%25s: %s", 'Expiration date', format_result(state, formatted_dte)
|
145
|
+
end
|
146
|
+
|
147
|
+
printf "%25s:\n", 'DNS'
|
148
|
+
result[:dns].each do |k,v|
|
149
|
+
v[:domains].each do |record|
|
150
|
+
if record[:type] == 'MX'
|
151
|
+
description = "#{record[:data][0]}: #{record[:data][1].to_s}"
|
152
|
+
else
|
153
|
+
description = record[:data].to_s
|
154
|
+
end
|
155
|
+
printf "%25s ", ''
|
156
|
+
printf "%5s".green, record[:type].to_s
|
157
|
+
printf "( ttl=%i ): %s\n", record[:ttl], description
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
@@ -0,0 +1,227 @@
|
|
1
|
+
require 'blend/status/team'
|
2
|
+
require 'blend/status/repo'
|
3
|
+
require 'blend/status/domain'
|
4
|
+
require 'blend/status/environment'
|
5
|
+
require 'blend/status/project_resolver'
|
6
|
+
|
7
|
+
module Blend
|
8
|
+
module Status
|
9
|
+
class Project
|
10
|
+
attr_accessor :name, :juice_id, :juice_client, :resolve
|
11
|
+
|
12
|
+
def initialize( name, resolve = false )
|
13
|
+
@name = name
|
14
|
+
@juice_client = Blend::Client.juice_client
|
15
|
+
reload
|
16
|
+
@resolve = resolve
|
17
|
+
@resolver = ProjectResolver.new( self )
|
18
|
+
end
|
19
|
+
|
20
|
+
def reload
|
21
|
+
@juice_id = @juice_client.project_id_from_name @name
|
22
|
+
@teams = nil
|
23
|
+
@repos = nil
|
24
|
+
@environment_status = nil
|
25
|
+
@domains_status = nil
|
26
|
+
@config = nil
|
27
|
+
@feeds = nil
|
28
|
+
@environments = nil
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
##
|
33
|
+
# Sub status systems
|
34
|
+
##
|
35
|
+
|
36
|
+
def team_status
|
37
|
+
@teams ||= (github_teams || []).collect do |team|
|
38
|
+
Team.new( self, team )
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def repo_status
|
43
|
+
@repos ||= (repos || []).collect do |name, repo|
|
44
|
+
Repo.new( self, name, repo )
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def environment_status
|
49
|
+
@environment_status ||= (servers || []).collect do |server|
|
50
|
+
Environment.new( self, server['name'], server['environment']['name'].downcase )
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def domains_status
|
55
|
+
@domains_status ||= domains.collect do |x|
|
56
|
+
Domain.new( @project, x[:environment], x[:domain] )
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
##
|
61
|
+
# Project Metadata
|
62
|
+
##
|
63
|
+
|
64
|
+
def domains
|
65
|
+
environment_status.collect do |x|
|
66
|
+
x.domains.collect do |domain|
|
67
|
+
{environment: x.environment, domain: domain }
|
68
|
+
end
|
69
|
+
end.flatten
|
70
|
+
end
|
71
|
+
|
72
|
+
def config
|
73
|
+
@config ||= (@juice_client.project( @juice_id ) || {})['blend_config']
|
74
|
+
end
|
75
|
+
|
76
|
+
def feeds
|
77
|
+
@feeds ||= @juice_client.feeds( @juice_id ).group_by { |x| x['feed_name'] }
|
78
|
+
end
|
79
|
+
|
80
|
+
def environments
|
81
|
+
@environments ||= @juice_client.environments( @juice_id ).group_by{|x| x['name'].downcase}
|
82
|
+
end
|
83
|
+
|
84
|
+
##
|
85
|
+
# Checks
|
86
|
+
##
|
87
|
+
|
88
|
+
def project_found
|
89
|
+
!@juice_id.nil? && @juice_id != ""
|
90
|
+
end
|
91
|
+
|
92
|
+
def read_only_teams
|
93
|
+
team_status.select { |team| team.read_only? }
|
94
|
+
end
|
95
|
+
|
96
|
+
def write_teams
|
97
|
+
team_status.select { |team| !team.read_only? }
|
98
|
+
end
|
99
|
+
|
100
|
+
def github_members
|
101
|
+
read_only_members = read_only_teams.collect { |ts| ts.members }.flatten
|
102
|
+
write_team_members = write_teams.collect { |ts| ts.members }.flatten
|
103
|
+
|
104
|
+
read_only_members -= write_team_members
|
105
|
+
|
106
|
+
write_team_members.collect do |x|
|
107
|
+
{name: x, access: :full}
|
108
|
+
end + read_only_members.collect do |x|
|
109
|
+
{name: x, access: :read}
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def repos
|
114
|
+
ret = {}
|
115
|
+
team_status.each do |x|
|
116
|
+
x.repos.each do |repo|
|
117
|
+
ret[repo.full_name] = repo
|
118
|
+
end
|
119
|
+
end
|
120
|
+
ret
|
121
|
+
end
|
122
|
+
|
123
|
+
def repos_setup
|
124
|
+
repos.keys
|
125
|
+
end
|
126
|
+
|
127
|
+
def source_control
|
128
|
+
a = (feeds['github'] || []).collect { |x| "#{x['namespace']}/#{x['name']}" }
|
129
|
+
b = repos_setup
|
130
|
+
|
131
|
+
return false if (a-b).length != 0 || (b-a).length != 0
|
132
|
+
return false if a.length == 0 || b.length == 0
|
133
|
+
return a
|
134
|
+
end
|
135
|
+
|
136
|
+
def juice_users_synced_diff
|
137
|
+
team_juice_users = {}
|
138
|
+
github_members.each do |member|
|
139
|
+
user = juice_client.user_from_github_user member[:name]
|
140
|
+
team_juice_users[user['id']] = user if user
|
141
|
+
end
|
142
|
+
|
143
|
+
juice_users = juice_client.project_users( @juice_id ).group_by{ |x| x['id'] }
|
144
|
+
|
145
|
+
not_in_juice = team_juice_users.keys - juice_users.keys
|
146
|
+
end
|
147
|
+
|
148
|
+
def juice_users_synced
|
149
|
+
juice_users_synced_diff.length == 0
|
150
|
+
end
|
151
|
+
|
152
|
+
def servers( env = nil )
|
153
|
+
if( env )
|
154
|
+
(feeds['heroku'] || []).group_by { |x| x['environment']['name'].downcase }[env]
|
155
|
+
else
|
156
|
+
feeds['heroku']
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def bugtracking
|
161
|
+
f = (feeds['asana'] || []) + (feeds['lighthouse'] || [])
|
162
|
+
return nil if f.length == 0
|
163
|
+
f
|
164
|
+
end
|
165
|
+
|
166
|
+
def production
|
167
|
+
environments['production']
|
168
|
+
end
|
169
|
+
|
170
|
+
def staging
|
171
|
+
environments['staging']
|
172
|
+
end
|
173
|
+
|
174
|
+
def heroku_apps( env = nil )
|
175
|
+
servers(env).collect { |x| [x['name'], x['environment']['name']]}
|
176
|
+
end
|
177
|
+
|
178
|
+
def hipchat
|
179
|
+
return nil if config.nil?
|
180
|
+
config['hipchat_room']
|
181
|
+
end
|
182
|
+
|
183
|
+
def github_teams
|
184
|
+
# return []] if @juice_id.nil?
|
185
|
+
return [] if config.nil?
|
186
|
+
config['teams']
|
187
|
+
end
|
188
|
+
|
189
|
+
def header text
|
190
|
+
puts
|
191
|
+
puts "#{text}".blue.underline
|
192
|
+
end
|
193
|
+
|
194
|
+
def check key, method
|
195
|
+
ret = __send__( method )
|
196
|
+
ret = false if ret.nil?
|
197
|
+
ret = false if ret.is_a? Array and ret.length == 0
|
198
|
+
|
199
|
+
pass = ret
|
200
|
+
|
201
|
+
if ret.is_a? Array
|
202
|
+
ret = ret.collect do |x|
|
203
|
+
if x.is_a? Hash
|
204
|
+
x[:name] || x['name']
|
205
|
+
else
|
206
|
+
x
|
207
|
+
end
|
208
|
+
end.join( ", ")
|
209
|
+
end
|
210
|
+
|
211
|
+
ret = "" if !ret
|
212
|
+
|
213
|
+
printf "%20s: ", key
|
214
|
+
if( pass )
|
215
|
+
printf "\u2713 #{ret}\n".encode('utf-8').green
|
216
|
+
else
|
217
|
+
printf "\u2718 #{ret}\n".encode('utf-8').red
|
218
|
+
if @resolve
|
219
|
+
r = "resolve_#{method}".to_sym
|
220
|
+
@resolver.__send__(r) if @resolver.respond_to? r
|
221
|
+
reload
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|