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
data/lib/blend/client.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'blend/client/hipchat_client'
|
2
|
+
require 'blend/client/github_client'
|
3
|
+
require 'blend/client/juice_client'
|
4
|
+
require 'blend/client/heroku_client'
|
5
|
+
|
6
|
+
module Blend
|
7
|
+
module Client
|
8
|
+
class << self
|
9
|
+
def hipchat_client
|
10
|
+
@hipchat_client ||= Blend::Client::HipchatClient.new( HipChat::API.new( get_token( :hipchat ) ) )
|
11
|
+
end
|
12
|
+
|
13
|
+
def github_client
|
14
|
+
@github_client ||= Blend::Client::GithubClient.new( Github.new( oauth_token: get_token( :github ) ) )
|
15
|
+
end
|
16
|
+
|
17
|
+
def juice_client( options = {} )
|
18
|
+
if( options[:auth_token] )
|
19
|
+
if( @juice_client && @juice_client.auth_token != options[:auth_token] )
|
20
|
+
@juice_client = nil
|
21
|
+
@hipchat_client = nil
|
22
|
+
@github_client = nil
|
23
|
+
end
|
24
|
+
|
25
|
+
@juice_client ||= Blend::Client::JuiceClient.new options
|
26
|
+
end
|
27
|
+
|
28
|
+
@juice_client ||= Blend::Client::JuiceClient.new
|
29
|
+
end
|
30
|
+
|
31
|
+
def heroku_client
|
32
|
+
@heroku_client ||= Blend::Client::HerokuClient.new( Heroku::API.new( api_key: get_token( :heroku ) ) )
|
33
|
+
end
|
34
|
+
|
35
|
+
def get_token( type )
|
36
|
+
token = case type
|
37
|
+
|
38
|
+
#when :juice
|
39
|
+
# Don't use this. This is already handled together with the login
|
40
|
+
# stuff in JuiceClient. It could be refactored to fit in with this
|
41
|
+
# method a little better, but what'd be the point? It works and
|
42
|
+
# it's straightforward.
|
43
|
+
when :hipchat
|
44
|
+
ENV['HIPCHAT_API_TOKEN'] || juice_client.hipchat_api
|
45
|
+
when :github
|
46
|
+
ENV['GITHUB_API_TOKEN'] || juice_client.auth( "github" )
|
47
|
+
when :heroku
|
48
|
+
# Opt for the organization-wide heroku api token:
|
49
|
+
ENV['HEROKU_API_TOKEN'] || juice_client.heroku_api
|
50
|
+
# Instead of per-user heroku auth:
|
51
|
+
#ENV['HEROKU_API_TOKEN'] || juice_client.auth( "heroku" )
|
52
|
+
else
|
53
|
+
throw "Unknown token type #{type}".red
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
throw "Token not found for #{type}" if token.nil? || token == ""
|
58
|
+
|
59
|
+
token
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
module Blend
|
2
|
+
module Client
|
3
|
+
class GithubClient
|
4
|
+
attr_accessor :client
|
5
|
+
|
6
|
+
def initialize( client )
|
7
|
+
@client = client
|
8
|
+
end
|
9
|
+
|
10
|
+
def list_repos( filter = nil )
|
11
|
+
return @repos if @repos && filter.nil?
|
12
|
+
|
13
|
+
repos = []
|
14
|
+
@client.repos.list( org: "sublimeguile" ).each_page do |page|
|
15
|
+
page.each do |r|
|
16
|
+
repos << r
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
if filter
|
21
|
+
repos = repos.select { |x| x['name'] =~ /#{filter}/ }
|
22
|
+
end
|
23
|
+
|
24
|
+
repos = repos.sort do |a,b|
|
25
|
+
a['name'] <=> b['name']
|
26
|
+
end
|
27
|
+
|
28
|
+
@repos = repos if filter.nil?
|
29
|
+
repos
|
30
|
+
end
|
31
|
+
|
32
|
+
def repo_create( team, name )
|
33
|
+
require 'pp'
|
34
|
+
pp @client.repos.create org: "sublimeguile", name: name, public: false, private: true
|
35
|
+
add_team_repo( team, "sublimeguile/#{name}" )
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
def list_collaborators( repo )
|
40
|
+
@client.repos.collaborators.list *repo.split( /\// )
|
41
|
+
end
|
42
|
+
|
43
|
+
def list_hooks( repo )
|
44
|
+
@client.repos.hooks.list( *repo.split( /\// ) )
|
45
|
+
end
|
46
|
+
|
47
|
+
def add_hook( repo, name, config )
|
48
|
+
@client.repos.hooks.create *repo.split( /\// ), name: name, config: config
|
49
|
+
end
|
50
|
+
|
51
|
+
def list_teams
|
52
|
+
@client.orgs.teams.list "sublimeguile"
|
53
|
+
end
|
54
|
+
|
55
|
+
def find_team_from_name( name )
|
56
|
+
list_teams.select { |x| x['name'] == name }
|
57
|
+
end
|
58
|
+
|
59
|
+
def list_team( team )
|
60
|
+
find_team_from_name( team ).first
|
61
|
+
end
|
62
|
+
|
63
|
+
def list_team_repos( team )
|
64
|
+
find_team_from_name(team).each do |x|
|
65
|
+
return @client.orgs.teams.repos x.id
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def list_team_members( team )
|
70
|
+
find_team_from_name(team).each do |x|
|
71
|
+
return @client.orgs.teams.list_members x.id
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def create_team( team )
|
76
|
+
@client.orgs.teams.create "sublimeguile", { name: team, permission: "push" }
|
77
|
+
end
|
78
|
+
|
79
|
+
def add_team_member( team, user )
|
80
|
+
find_team_from_name( team ).each do |x|
|
81
|
+
return @client.orgs.teams.add_member x.id, user
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def remove_team_member( team, user)
|
86
|
+
find_team_from_name( team ).each do |x|
|
87
|
+
return @client.orgs.teams.remove_member x.id, user
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def add_team_repo( team, repo )
|
92
|
+
user,name = repo.split( /\// )
|
93
|
+
find_team_from_name( team ).each do |x|
|
94
|
+
return @client.orgs.teams.add_repo x.id, user, name
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def remove_team_repo( team, repo )
|
99
|
+
user,name = repo.split( /\// )
|
100
|
+
find_team_from_name( team ).each do |x|
|
101
|
+
return @client.orgs.teams.remove_repo x.id, user, name
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'highline/import'
|
2
|
+
|
3
|
+
module Blend
|
4
|
+
module Client
|
5
|
+
class HerokuClient
|
6
|
+
|
7
|
+
attr_accessor :client
|
8
|
+
|
9
|
+
def initialize( client )
|
10
|
+
@client = client
|
11
|
+
@addons = {}
|
12
|
+
end
|
13
|
+
|
14
|
+
def info( app )
|
15
|
+
client.get_app(app).body
|
16
|
+
end
|
17
|
+
|
18
|
+
def domains( app )
|
19
|
+
client.get_domains(app).body
|
20
|
+
end
|
21
|
+
|
22
|
+
def nonheroku_domains( app )
|
23
|
+
domains(app).reject{|x| x['base_domain']=="herokuapp.com" || x['domain'] =~ /^www/}.collect{|x| x['domain']}
|
24
|
+
end
|
25
|
+
|
26
|
+
def addons( app, filter=nil )
|
27
|
+
@addons[app] ||= client.get_addons(app).body
|
28
|
+
if filter.nil?
|
29
|
+
@addons[app]
|
30
|
+
else
|
31
|
+
@addons[app].select{|x| x['name'] =~ filter}
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def addon_names( app, filter )
|
36
|
+
addons(app, filter).collect do |addon|
|
37
|
+
name,plan = addon['name'].split(/:/)
|
38
|
+
{name: name, plan: plan}
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def addon_matches( app, addon_name )
|
43
|
+
addons(app).select{|x| x[:name] =~ addon_name}
|
44
|
+
end
|
45
|
+
|
46
|
+
def stack(app)
|
47
|
+
info(app)['stack']
|
48
|
+
end
|
49
|
+
|
50
|
+
def dynos( app )
|
51
|
+
info(app)['dynos']
|
52
|
+
end
|
53
|
+
|
54
|
+
def backups( app )
|
55
|
+
addon_names(app, /pgbackups/)
|
56
|
+
end
|
57
|
+
|
58
|
+
def databases( app )
|
59
|
+
addon_names(app, /postgresq/)
|
60
|
+
end
|
61
|
+
|
62
|
+
def run_domain_checker( app )
|
63
|
+
results = {}
|
64
|
+
nonheroku_domains(app).map{|x| x['domain']}.each do |d|
|
65
|
+
|
66
|
+
|
67
|
+
DomainChecker.check(d)
|
68
|
+
|
69
|
+
result = {}
|
70
|
+
results[d] = result
|
71
|
+
|
72
|
+
# Check registered
|
73
|
+
result[:registered] = dc.registered?
|
74
|
+
|
75
|
+
# Check registrar
|
76
|
+
result[:registrar] = dc.registrar
|
77
|
+
|
78
|
+
result[:ssl] = dc.ssl
|
79
|
+
end
|
80
|
+
|
81
|
+
results
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module Blend
|
2
|
+
module Client
|
3
|
+
class HipchatClient
|
4
|
+
attr_accessor :api
|
5
|
+
|
6
|
+
def initialize( api )
|
7
|
+
@api = api
|
8
|
+
end
|
9
|
+
|
10
|
+
def create_room( name, topic )
|
11
|
+
creator = user_by_name 'Will Schenk'
|
12
|
+
|
13
|
+
ret = api.rooms_create name, creator['user_id'], 'public', topic
|
14
|
+
|
15
|
+
if ret["error"]
|
16
|
+
pp ret["error"]
|
17
|
+
end
|
18
|
+
|
19
|
+
@rooms = nil
|
20
|
+
end
|
21
|
+
|
22
|
+
def rooms
|
23
|
+
@rooms ||= api.rooms_list.parsed_response['rooms']
|
24
|
+
raise Exceptions::HipchatAuthenticationFailure if @rooms.nil?
|
25
|
+
@rooms
|
26
|
+
end
|
27
|
+
|
28
|
+
def room_name_from_xmpp_jid( name )
|
29
|
+
rooms.select{|x| x['xmpp_jid'] == name}.first['name'] rescue nil
|
30
|
+
end
|
31
|
+
|
32
|
+
def room_by_name( name )
|
33
|
+
rooms.each do |r|
|
34
|
+
return r if r['name'] == name
|
35
|
+
end
|
36
|
+
|
37
|
+
puts "Room #{name} not found".red
|
38
|
+
nil
|
39
|
+
end
|
40
|
+
|
41
|
+
def room_info( name )
|
42
|
+
room = room_by_name name
|
43
|
+
|
44
|
+
if( room )
|
45
|
+
api.rooms_show( room['room_id'] ).parsed_response['room']
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def users
|
50
|
+
@users ||= api.users_list.parsed_response['users']
|
51
|
+
end
|
52
|
+
|
53
|
+
def user_by_name( name )
|
54
|
+
users.each do |u|
|
55
|
+
return u if u['name'] == name
|
56
|
+
end
|
57
|
+
|
58
|
+
puts "User #{name} not found".red
|
59
|
+
end
|
60
|
+
|
61
|
+
def set_topic( room, topic )
|
62
|
+
room = room_by_name room
|
63
|
+
|
64
|
+
if room
|
65
|
+
api.rooms_topic( room['room_id'], topic)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def post_message( room, message, color = 'yellow', notify = false, type = 'text' )
|
70
|
+
room = room_by_name room
|
71
|
+
|
72
|
+
if room
|
73
|
+
api.rooms_message room['room_id'], 'hfc', message, notify ? "1" : "0", color, type
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,400 @@
|
|
1
|
+
require 'highline/import'
|
2
|
+
|
3
|
+
module Blend
|
4
|
+
module Client
|
5
|
+
class JuiceClient
|
6
|
+
include HTTParty
|
7
|
+
|
8
|
+
class << self
|
9
|
+
|
10
|
+
# Wrap HHTParty's get method so we can actually catch errors
|
11
|
+
def get( url, *args )
|
12
|
+
response = super( url, *args )
|
13
|
+
case response.code
|
14
|
+
when 401
|
15
|
+
raise Exceptions::AuthenticationFailure
|
16
|
+
end
|
17
|
+
return response
|
18
|
+
end
|
19
|
+
|
20
|
+
def post( url, *args )
|
21
|
+
response = super( url, *args )
|
22
|
+
case response.code
|
23
|
+
when 401
|
24
|
+
raise Exceptions::AuthenticationFailure
|
25
|
+
end
|
26
|
+
return response
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
def initialize(opts={})
|
32
|
+
@options = {}
|
33
|
+
@options['auth_token'] = opts[:auth_token] if opts.include? :auth_token
|
34
|
+
end
|
35
|
+
|
36
|
+
base_uri ENV['JUICE_API_ENDPOINT'] || 'http://happyfunjuice.com/api'
|
37
|
+
# debug_output $stderr
|
38
|
+
|
39
|
+
def login
|
40
|
+
query_login
|
41
|
+
end
|
42
|
+
|
43
|
+
def logout
|
44
|
+
destroy_auth_token
|
45
|
+
end
|
46
|
+
|
47
|
+
def create_project( name )
|
48
|
+
auth_token
|
49
|
+
pp self.class.post "/organizations/1/projects", { query: { "project[name]" => name } }
|
50
|
+
@projects = nil
|
51
|
+
end
|
52
|
+
|
53
|
+
def profile
|
54
|
+
auth_token
|
55
|
+
@projects ||= self.class.get( "/user.json" )
|
56
|
+
end
|
57
|
+
|
58
|
+
def projects
|
59
|
+
auth_token
|
60
|
+
@projects ||= self.class.get( "/projects.json" ).each do |x|
|
61
|
+
x['blend_config'] ||= {}
|
62
|
+
x['blend_config']['teams'] ||= []
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def summary
|
67
|
+
auth_token
|
68
|
+
@projects ||= self.class.get( "/projects/summary.json" ).each do |x|
|
69
|
+
x['blend_config'] ||= {}
|
70
|
+
x['blend_config']['teams'] ||= []
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def organizations
|
75
|
+
auth_token
|
76
|
+
@organizations ||= self.class.get( "/organizations.json" ).each do |o|
|
77
|
+
o['blend_config'] ||= {}
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def project_info_from_room( room )
|
82
|
+
auth_token
|
83
|
+
if room =~ /[0-9]+_[^@]+@.*/
|
84
|
+
room_name = Blend::Client.hipchat_client.room_name_from_xmpp_jid( room )
|
85
|
+
else
|
86
|
+
room_name = room
|
87
|
+
end
|
88
|
+
return nil if room_name.nil? or room_name.length==0
|
89
|
+
projects.select{|x| (x['blend_config']['hipchat_room'].downcase rescue nil) == room_name.downcase}.first
|
90
|
+
end
|
91
|
+
|
92
|
+
def project_id_from_room( room )
|
93
|
+
@project_ids_from_rooms ||= {}
|
94
|
+
p = project_info_from_room( room )
|
95
|
+
if p.nil?
|
96
|
+
nil
|
97
|
+
else
|
98
|
+
@project_ids_from_rooms[room] ||= p['id']
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def project_id_from_name( name )
|
103
|
+
return name if name.to_s =~ /^[0-9]+$/
|
104
|
+
|
105
|
+
projects.each do |project|
|
106
|
+
return project['id'] if project['name'].projectize == name.projectize
|
107
|
+
end
|
108
|
+
|
109
|
+
puts "Couldn't find project #{name.projectize}"
|
110
|
+
nil
|
111
|
+
end
|
112
|
+
|
113
|
+
def project( id )
|
114
|
+
return nil if id.nil?
|
115
|
+
|
116
|
+
auth_token
|
117
|
+
data = self.class.get "/projects/#{id}.json"
|
118
|
+
|
119
|
+
data['blend_config'] ||= {}
|
120
|
+
data['blend_config']['teams'] ||= []
|
121
|
+
|
122
|
+
data
|
123
|
+
end
|
124
|
+
|
125
|
+
def lookup_user( query )
|
126
|
+
auth_token
|
127
|
+
self.class.get "/users/lookup.json", { query: { query: query } }
|
128
|
+
end
|
129
|
+
|
130
|
+
def search_users( query )
|
131
|
+
auth_token
|
132
|
+
self.class.get "/users/search.json", { query: { query: query } }
|
133
|
+
end
|
134
|
+
|
135
|
+
def user_from_github_user( github )
|
136
|
+
@github_users ||= {}
|
137
|
+
@github_users[github] ||= search_users(github).select { |x| x['github_handle'] == github }.first
|
138
|
+
end
|
139
|
+
|
140
|
+
def organization_users( id )
|
141
|
+
auth_token
|
142
|
+
self.class.get "/organizations/#{id}/users.json"
|
143
|
+
end
|
144
|
+
|
145
|
+
def project_users( id )
|
146
|
+
auth_token
|
147
|
+
self.class.get "/projects/#{id}/users.json"
|
148
|
+
end
|
149
|
+
|
150
|
+
def project_add_user( project_id, user_id )
|
151
|
+
auth_token
|
152
|
+
self.class.post "/projects/#{project_id}/users/#{user_id}"
|
153
|
+
end
|
154
|
+
|
155
|
+
def project_config( id, config = nil )
|
156
|
+
auth_token
|
157
|
+
if( config.nil? )
|
158
|
+
puts "Loading config"
|
159
|
+
project = self.class.get "/projects/#{id}.json"
|
160
|
+
project['blend_config'] || {}
|
161
|
+
else
|
162
|
+
puts "Setting config #{config}"
|
163
|
+
self.class.put "/projects/#{id}.json", { query: { project: { blend_config: config } } }
|
164
|
+
@projects = nil
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
def project_add_team( id, github_team )
|
169
|
+
config = project_config( id )
|
170
|
+
config['teams'] ||= []
|
171
|
+
config['teams'] << github_team
|
172
|
+
project_config( id, config )
|
173
|
+
end
|
174
|
+
|
175
|
+
def project_add_hipchat( id, hipchat )
|
176
|
+
config = project_config( id )
|
177
|
+
config['hipchat_room'] = hipchat
|
178
|
+
project_config( id, config )
|
179
|
+
end
|
180
|
+
|
181
|
+
def feeds( id )
|
182
|
+
auth_token
|
183
|
+
self.class.get "/projects/#{id}/feeds.json"
|
184
|
+
end
|
185
|
+
|
186
|
+
def add_feed( project_id, feed_type, key, environment = nil )
|
187
|
+
auth_token
|
188
|
+
self.class.post "/projects/#{project_id}/feeds", {query: { feed_type: feed_type, key: key } }
|
189
|
+
end
|
190
|
+
|
191
|
+
def environments( id )
|
192
|
+
auth_token
|
193
|
+
self.class.get "/projects/#{id}/environments.json"
|
194
|
+
end
|
195
|
+
|
196
|
+
def heroku_apps( id )
|
197
|
+
auth_token
|
198
|
+
f = feeds( id ).group_by{|x| x['feed_name']}
|
199
|
+
(f['heroku'] || []).group_by { |x| x['environment']['name'].downcase}
|
200
|
+
end
|
201
|
+
|
202
|
+
def auths
|
203
|
+
auth_token
|
204
|
+
@auths ||= self.class.get "/profile/authentications.json"
|
205
|
+
end
|
206
|
+
|
207
|
+
def auth( provider )
|
208
|
+
auths.select do |x|
|
209
|
+
return x['token'] if x['provider'] == provider
|
210
|
+
end
|
211
|
+
|
212
|
+
nil
|
213
|
+
end
|
214
|
+
|
215
|
+
def activities( project_id, after, before = Time.now )
|
216
|
+
auth_token
|
217
|
+
activities = self.class.get "/projects/#{project_id}/activities.json", {query: { after: after.to_i, before: before.to_i } }
|
218
|
+
activities_stats activities, after, before # <-- so activities actually returns activities_stats? That's... weird.
|
219
|
+
end
|
220
|
+
|
221
|
+
def activities_stats( activities, after, before )
|
222
|
+
stats = { type: {},
|
223
|
+
actors_activites: {},
|
224
|
+
activities: activities,
|
225
|
+
after: after,
|
226
|
+
before: before,
|
227
|
+
active_tickets: {},
|
228
|
+
closed_tickets: {}}
|
229
|
+
|
230
|
+
activities.each do |x|
|
231
|
+
x['happened_at'] = Time.parse x['happened_at']
|
232
|
+
end.sort do |a,b|
|
233
|
+
a['happened_at'] <=> b['happened_at']
|
234
|
+
end.each do |a|
|
235
|
+
actor = a['actor_identifier']
|
236
|
+
type = a['activity_type']
|
237
|
+
stats[:type][type] ||= []
|
238
|
+
stats[:type][type] << a
|
239
|
+
|
240
|
+
if( !(type =~ /^juice/) && !(type =~ /tweet/) )
|
241
|
+
stats[:actors_activites][type] ||= {}
|
242
|
+
stats[:actors_activites][type][actor] ||= []
|
243
|
+
stats[:actors_activites][type][actor] << a
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
stats
|
248
|
+
end
|
249
|
+
|
250
|
+
def heroku_api( token = nil )
|
251
|
+
auth_token
|
252
|
+
ret = {}
|
253
|
+
if( token )
|
254
|
+
ret = self.class.post "/organizations/1/heroku/api_token.json", {query: {heroku_api_token: token}}
|
255
|
+
else
|
256
|
+
ret = self.class.get "/organizations/1/heroku/api_token.json"
|
257
|
+
end
|
258
|
+
ret['heroku_api_token']
|
259
|
+
end
|
260
|
+
|
261
|
+
|
262
|
+
def hipchat_api( token = nil )
|
263
|
+
auth_token
|
264
|
+
ret = {}
|
265
|
+
if( token )
|
266
|
+
ret = self.class.post "/organizations/1/hipchat/auth_token.json", {query: {hipchat_auth_token: token}}
|
267
|
+
else
|
268
|
+
ret = self.class.get "/organizations/1/hipchat/auth_token.json"
|
269
|
+
end
|
270
|
+
ret['hipchat_auth_token']
|
271
|
+
end
|
272
|
+
|
273
|
+
def hipchat_check
|
274
|
+
hipchat_client = Blend::Client.hipchat_client
|
275
|
+
|
276
|
+
rooms = {}
|
277
|
+
hipchat_client.rooms.each { |x| rooms[x['name']] = [] }
|
278
|
+
|
279
|
+
projects.each do |project|
|
280
|
+
room = project['blend_config']['hipchat_room']
|
281
|
+
if room
|
282
|
+
rooms[room] ||= []
|
283
|
+
rooms[room] << project['name']
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
287
|
+
rooms.keys.sort { |a,b| a <=> b }.collect do |room|
|
288
|
+
if rooms[room].size == 0
|
289
|
+
rooms[room] << "_unassigned_"
|
290
|
+
end
|
291
|
+
{ room: room, projects: rooms[room] }
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
def github_team_check
|
296
|
+
github_client = Blend::Client.github_client
|
297
|
+
|
298
|
+
teams = {}
|
299
|
+
github_client.list_teams.each do |team|
|
300
|
+
teams[team.name] = []
|
301
|
+
end
|
302
|
+
|
303
|
+
projects.each do |project|
|
304
|
+
project['blend_config']['teams'].each do |x|
|
305
|
+
teams[x] << project
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
teams
|
310
|
+
end
|
311
|
+
|
312
|
+
|
313
|
+
def config_file
|
314
|
+
"#{ENV['HOME']}/.juice.yml"
|
315
|
+
end
|
316
|
+
|
317
|
+
def destroy_auth_token
|
318
|
+
_prev_options = @options
|
319
|
+
begin
|
320
|
+
return File.delete config_file
|
321
|
+
rescue Errno::ENOENT
|
322
|
+
raise Exceptions::AlreadyLoggedOut
|
323
|
+
ensure
|
324
|
+
@options = {}
|
325
|
+
end
|
326
|
+
_prev_options
|
327
|
+
end
|
328
|
+
|
329
|
+
|
330
|
+
def check_credentials( username, password )
|
331
|
+
response = self.class.post '/auth', {body: {username: username, password: password}}
|
332
|
+
raise Exceptions::LoginAuthenticationFailure if response['auth_token'].nil?
|
333
|
+
@options = response.parsed_response if @options['auth_token'].nil?
|
334
|
+
end
|
335
|
+
|
336
|
+
|
337
|
+
def query_login
|
338
|
+
|
339
|
+
begin
|
340
|
+
response = read_auth_token
|
341
|
+
@options = response
|
342
|
+
|
343
|
+
# If it doesn't contain an auth_token, it's as good as not existing:
|
344
|
+
|
345
|
+
raise Exceptions::AlreadyLoggedIn
|
346
|
+
|
347
|
+
rescue Errno::ENOENT
|
348
|
+
username = ask( "Username : " ) { |q| q.echo = true }
|
349
|
+
password = ask( "Password : " ) { |q| q.echo = '.' }
|
350
|
+
|
351
|
+
@options = check_credentials( username, password )
|
352
|
+
|
353
|
+
write_auth_token( @options )
|
354
|
+
end
|
355
|
+
end
|
356
|
+
|
357
|
+
|
358
|
+
def read_auth_token
|
359
|
+
begin
|
360
|
+
response = YAML.load( File.read( config_file ) )
|
361
|
+
raise StandardError.new unless response['auth_token']
|
362
|
+
response
|
363
|
+
rescue StandardError
|
364
|
+
raise Errno::ENOENT
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
|
369
|
+
def write_auth_token( options )
|
370
|
+
File.open( config_file, "w" ) do |o|
|
371
|
+
o.puts YAML.dump( options || {} )
|
372
|
+
end
|
373
|
+
return options
|
374
|
+
end
|
375
|
+
|
376
|
+
|
377
|
+
def auth_token
|
378
|
+
|
379
|
+
# Just return it if it's been set manually. This is accomplished when client is
|
380
|
+
# instantiated with JuiceClient.new(auth_token: ---)
|
381
|
+
if !@options['auth_token'].nil?
|
382
|
+
self.class.default_params auth_token: @options['auth_token']
|
383
|
+
return @options['auth_token']
|
384
|
+
end
|
385
|
+
|
386
|
+
if ENV['JUICE_AUTH_TOKEN'].nil?
|
387
|
+
begin
|
388
|
+
query_login
|
389
|
+
rescue Exceptions::AlreadyLoggedIn
|
390
|
+
end
|
391
|
+
else
|
392
|
+
@options = { 'auth_token' => ENV['JUICE_AUTH_TOKEN'] }
|
393
|
+
end
|
394
|
+
self.class.default_params auth_token: @options['auth_token']
|
395
|
+
@options['auth_token']
|
396
|
+
end
|
397
|
+
|
398
|
+
end
|
399
|
+
end
|
400
|
+
end
|