blend 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|