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.
@@ -0,0 +1,493 @@
1
+ module Blend
2
+ module CLI
3
+ class Juice < Thor
4
+ desc "login", "Login to juice"
5
+ def login
6
+ puts "Logged in." if client.login
7
+ end
8
+
9
+ desc "logout", "Clear juice credentials"
10
+ def logout
11
+ puts "Juice credentials cleared." if client.logout
12
+ end
13
+
14
+ desc "open PROJECT", "Open up juice"
15
+ def open( name )
16
+ project_id = project_id_from_name name
17
+ if( project_id.nil? )
18
+ puts "#{name} not found"
19
+ return
20
+ end
21
+
22
+ system "open http://happyfunjuice.com/projects/#{project_id}"
23
+ end
24
+
25
+ desc "settings PROJECT", "Open up juice settings"
26
+ def settings(name)
27
+ project_id = project_id_from_name name
28
+ if( project_id.nil? )
29
+ puts "#{name} not found"
30
+ return
31
+ end
32
+
33
+ system "open http://happyfunjuice.com/projects/#{project_id}/overview"
34
+ end
35
+
36
+ desc "create PROJECT", "Create a juice project"
37
+ def create( name )
38
+ puts "TIP: you can also run check #{name} to set up everything"
39
+ client.create_project( name )
40
+ end
41
+
42
+ desc "projects", "List juice projects"
43
+ def projects
44
+ puts
45
+ printf "%-25s %-10s %-10s %-25s\n".blue, '', 'Commits', 'Deploys', '', ''
46
+ printf "%-25s %-10s %-10s %-25s\n".blue, '', 'this', 'this', '', ''
47
+ printf "%-25s %-10s %-10s %-25s %s\n".underline.blue, 'Name', 'wk', 'wk', 'Hipchat room', 'Teams'
48
+ client.summary.sort{|a,b| b['name'].to_i <=> a['name'].to_i}.each_with_index do |project,i|
49
+ printf "%-25s %-10s %-10s %-25s %s\n".try{|x| i%4==3 ? x.underline : x},
50
+ #project['id'],
51
+ project['name'].projectize,
52
+ (project['has_source_feeds'] ? project['commits_this_week'] : ''),
53
+ (project['has_server_feeds'] ? project['deploys_this_week'] : ''),
54
+ project['blend_config']['hipchat_room'],
55
+ project['blend_config']['teams'].join( ',' )
56
+ end
57
+ puts
58
+ end
59
+
60
+ desc "organizations", "Get a list of your organizations"
61
+ def organizations
62
+ puts
63
+ printf "%-5s %-25s %-25s\n".underline.blue, 'ID', 'Name', 'Domain name'
64
+ client.organizations.each do |o|
65
+ printf "%-5s %-25s %-25s\n", o['id'], o['name'], o['domain_name']
66
+ end
67
+ puts
68
+ end
69
+
70
+
71
+ desc "feeds PROJECT", "Show the configured juice feeds"
72
+ def feeds(name)
73
+ puts
74
+ printf "%-30s %-20s %-30s\n".blue.underline, 'Feed', 'Environment', 'Namespace'
75
+ client.feeds( project_id_from_name( name ) ).sort do
76
+ |a,b| a['feed_name'] <=> b['feed_name']
77
+ end.each do |feed|
78
+ printf "%-30s %-20s %-30s\n",
79
+ feed['feed_name'],
80
+ (feed['environment'] || {})['name'],
81
+ [feed['namespace'],feed['name']].select {|x| x}.join( '/' )
82
+ end
83
+ puts
84
+ end
85
+
86
+ desc "users [PROJECT]", "Get a list of users"
87
+ def users( name=nil )
88
+
89
+ if name.nil?
90
+ _users = client.organization_users( 1 ) # Hard-code hfc org here
91
+ else
92
+ _users = client.project_users( project_id_from_name( name ) )
93
+ end
94
+
95
+ puts
96
+ printf "%-25s %35s %35s %35s %35s\n".blue.underline, 'Name', 'Email', 'Personal email', 'Heroku', 'Github'
97
+ _users.each do |u|
98
+ printf "%-25s %35s %35s %35s %35s\n", u['name'], u['email'], u['personal_email'], u['heroku_handle'], u['github_handle']
99
+ end
100
+ puts
101
+ end
102
+
103
+ desc "add_team PROJECT TEAM", "Add a github team to a project"
104
+ def add_team( name, team )
105
+ client.project_add_team( project_id_from_name( name ), team )
106
+ info( name )
107
+ end
108
+
109
+ desc "add_hipchat PROJECT ROOM", "Add a hipchat room to a project"
110
+ def add_hipchat( name, room )
111
+ client.project_add_hipchat( project_id_from_name( name ), room )
112
+ info( name )
113
+ end
114
+
115
+ desc "lookup_user NAME", "Looks up a user by email address"
116
+ def lookup_user( query )
117
+ pp client.lookup_user( query )
118
+ end
119
+
120
+ desc "search_users QUERY", "Look up a user by name, email, github, heroku, etc."
121
+ def search_users( query )
122
+ puts
123
+ printf "%-25s %35s %35s %35s %35s\n".blue.underline, 'Name', 'Email', 'Personal email', 'Heroku', 'Github'
124
+ client.search_users(query).each do |u|
125
+ printf "%-25s %35s %35s %35s %35s\n", u['name'], u['email'], u['personal_email'], u['heroku_handle'], u['github_handle']
126
+ end
127
+ puts
128
+ end
129
+
130
+ # desc "user_set FIELD VALUE", "Set the value of a particular field for a user"
131
+ # def user_set( field, value )
132
+ # client
133
+ # end
134
+
135
+ desc "heroku_api TOKEN", "Sets the organization heroku token"
136
+ def heroku_api( token )
137
+ client.heroku_api token
138
+ end
139
+
140
+
141
+ desc "hipchat_api TOKEN", "Sets the organization hipchat token"
142
+ def hipchat_api( token )
143
+ client.hipchat_api token
144
+ end
145
+
146
+ desc "all_projects [--resolve]", "Show all project status"
147
+ option :resolve
148
+ def all_projects
149
+ client.projects.each do |p|
150
+ project( p['name'] )
151
+ end
152
+ end
153
+
154
+ desc "project NAME [--resolve]", "Get project status"
155
+ option :resolve
156
+ def project( name )
157
+ status = Blend::Status::Project.new( name, options[:resolve] )
158
+
159
+ status.header "#{name}: Juice Configuration"
160
+ status.check "Project Exists", :project_found
161
+ status.check "Hipchat Room", :hipchat
162
+ status.check "Github Teams", :github_teams
163
+ status.check "Repos Configured", :repos_setup
164
+ status.check "Source Control", :source_control
165
+ status.check "Bug Tracking", :bugtracking
166
+
167
+ status.header "#{name}: Environments"
168
+ status.check "Production", :production
169
+ status.check "Staging", :staging
170
+
171
+ status.header "#{name}: Team Configuration (#{status.github_teams.join(',')})" if status.github_teams.length > 0
172
+
173
+ status.check "Members", :github_members
174
+
175
+ status.check "User Matchup", :juice_users_synced
176
+
177
+ status.github_members.each do |m|
178
+ member = m[:name]
179
+ access = m[:access]
180
+ # puts member
181
+ juice_user = client.user_from_github_user member
182
+ if access == :read
183
+ printf "%-20s %15s".yellow, member, "readonly"
184
+ else
185
+ printf "%-20s %15s".green, member, "fullaccess"
186
+ end
187
+
188
+ if juice_user
189
+ printf " %-20s %s\n", juice_user['name'], juice_user['email']
190
+ else
191
+ puts " Unknown to juice".red
192
+ end
193
+ end
194
+
195
+ status.repo_status.each do |repo|
196
+ status.header "#{repo.name} Configuration"
197
+
198
+ repo.check "Private", :private?
199
+ repo.check "Hipchat Deployhook", :hipchat_hook
200
+ end
201
+
202
+ status.environment_status.each do |env|
203
+ status.header "Server: #{env.server} Configuration"
204
+
205
+ env.check "Dyno Redundancy", :dyno_redundancy
206
+ env.check "Database", :database
207
+ env.check "Backups", :backups
208
+ env.check "Stack", :stack
209
+ env.check "Exception Handling", :exception_handling
210
+ env.check "Deploy Hooks", :deployhooks
211
+ env.check "Log Monitoring", :log_monitoring
212
+ env.check "App Monitoring", :app_monitoring
213
+ env.check "SSL Addon", :ssl
214
+ end
215
+
216
+ status.domains_status.each do |domain|
217
+ status.header "DNS: #{domain.domain} configuration"
218
+
219
+ domain.check "Registered?", :registered?
220
+ domain.check "Expires", :expires
221
+ domain.check "Owner", :owner
222
+ domain.check "SSL Cert", :ssl_exists?
223
+ domain.check "SSL Expires", :ssl_valid_until
224
+ domain.check "SSL Common Name", :ssl_common_name
225
+ end
226
+
227
+ end
228
+ =begin
229
+
230
+
231
+
232
+
233
+ desc "check [PROJECT]", "Check a project config (all the checks)"
234
+ def check( name )
235
+ check_project( name )
236
+ puts
237
+ check_hipchat( name )
238
+ puts
239
+ check_team( name )
240
+ puts
241
+ check_hooks( name )
242
+ puts
243
+ info( name )
244
+ end
245
+
246
+ desc "check_hooks [PROJECT]", "Check to see if the hooks are configured"
247
+ def check_hooks( name )
248
+ puts "Looking for github hooks".bold
249
+ ##
250
+ # Github Hooks
251
+ ##
252
+ project_id = project_id_from_name name
253
+ return if project_id.nil?
254
+
255
+ data = client.project project_id
256
+ config = data['blend_config']
257
+
258
+ teams = config['teams']
259
+
260
+ if teams.count > 0
261
+ teams.each do |team|
262
+ puts "Looking at repos for #{team}".bold
263
+ github_client.list_team_repos( team ).each do |repo|
264
+ printf "%-40s %s\n", repo['full_name'], repo['description']
265
+ found = {}
266
+ github_client.list_hooks( repo['full_name'] ).each do |hook|
267
+ puts "Found #{hook["name"]}"
268
+ found[hook['name']] = true
269
+ end
270
+
271
+ unless found['hipchat']
272
+ puts "Missing hipchat hook"
273
+ if config['hipchat_room']
274
+ puts "Adding Hipchat Hook"
275
+ Blend::CLI::Github.new.add_hipchat( repo['full_name'], config['hipchat_room'])
276
+ else
277
+ puts "Missing hipchat room"
278
+ end
279
+ end
280
+ end
281
+ end
282
+ else
283
+ puts "Teams must be set up correctly in order to monitor hooks.".red
284
+ end
285
+
286
+ apps = client.heroku_apps( project_id )
287
+
288
+
289
+ if( apps['production'] )
290
+ puts "Production".blue
291
+ apps['production'].each do |app|
292
+ Blend::CLI::Heroku.new.check app['name']
293
+ a = heroku_client.addons(app['name'], /deployhooks/)
294
+
295
+ if( a.nil? || a.length == 0 )
296
+ puts "Adding deploy hook".yellow
297
+ system( "echo heroku addons:add deployhooks:hipchat --auth_token=#{client.hipchat_api} --room=\"#{config['hipchat_room']} --app #{app['name']}\"")
298
+ system( "heroku addons:add deployhooks:hipchat --auth_token=#{client.hipchat_api} --room=\"#{config['hipchat_room']}\" --app #{app['name']}")
299
+ Blend::Client::hipchat_client.post_message config['hipchat_room'], "Heroku app: #{app['name']} commit hook now added"
300
+ end
301
+ end
302
+ end
303
+ if( apps['staging'] )
304
+ puts "Staging".blue
305
+ apps['staging'].each do |app|
306
+ Blend::CLI::Heroku.new.check app['name']
307
+ a = heroku_client.addons(app['name'], /deployhooks/)
308
+
309
+ if( a.nil? || a.length == 0 )
310
+ puts "Adding deploy hook".yellow
311
+ system( "echo heroku addons:add deployhooks:hipchat --auth_token=#{client.hipchat_api} --room=\"#{config['hipchat_room']} --app #{app['name']}\"")
312
+ system( "heroku addons:add deployhooks:hipchat --auth_token=#{client.hipchat_api} --room=\"#{config['hipchat_room']} --app #{app['name']}\"")
313
+ Blend::Client::hipchat_client.post_message config['hipchat_room'], "Heroku app: #{app['name']} commit hook now added"
314
+ end
315
+ end
316
+ end
317
+
318
+ end
319
+ =end
320
+
321
+ desc "hipchat_check", "Prints out all the rooms not assigned to rooms"
322
+ def hipchat_check
323
+ begin
324
+ client.hipchat_check.each do |x|
325
+ printf "%-30s %s\n", x[:room], x[:projects].join( "," )
326
+ end
327
+ rescue Exceptions::HipchatAuthenticationFailure
328
+ puts "Unable to connect to Hipchat. Is your key valid?".red
329
+ end
330
+ end
331
+
332
+ desc "github_team_check", "Prints out all the teams not assigned to projects"
333
+ option :fix
334
+ def github_team_check
335
+ client.github_team_check.each do |team,projects|
336
+ next if team == 'Owners'
337
+ next if projects.size > 0
338
+ puts "#{team} has no juice project".red
339
+ # printf "%-30s %s\n", team, projects.collect {|x| x['name'] }.join( "," )
340
+
341
+ if( options[:fix] )
342
+ choices = client.projects.collect { |x| x['name'] }
343
+
344
+ project = choose do |menu|
345
+ menu.header = "Select a github team action"
346
+ menu.prompt = "Please choose a unassigned juice project to associate #{team} with:"
347
+
348
+ menu.choice "Ignore" do
349
+ "ignore"
350
+ end
351
+
352
+ menu.choice "Create a project called #{team}" do
353
+ "create"
354
+ end
355
+
356
+ menu.choices *choices
357
+ end
358
+
359
+ if( project == "ignore" )
360
+ puts "Skip it"
361
+ else
362
+ if( project == "create" )
363
+ puts "TODO: Create a new project called #{team}"
364
+ else
365
+ add_team project, team
366
+ # puts "Attaching to: #{project}"
367
+ end
368
+ end
369
+ end
370
+ end
371
+ end
372
+
373
+ desc "activity PROJECT", "Shows recent project activity in last week or (default) current week [--lastweek] [--thisweek]"
374
+ option :lastweek
375
+ option :thisweek
376
+ def activity( name )
377
+ puts
378
+ project_id = project_id_from_name name
379
+ return if project_id.nil?
380
+
381
+ now = DateTime.now.to_date + 1
382
+ after = now - now.wday
383
+ before = Time.now
384
+
385
+ if( options[:lastweek] )
386
+ after -= 7
387
+ before = after + 7
388
+ end
389
+
390
+ summary = client.activities( project_id, after.to_time, before.to_time )
391
+
392
+ project = client.project( project_id )
393
+
394
+ puts "#{project['name']} activity".bold + " for #{summary[:after].strftime( "%Y-%m-%d %H:%M" )} (#{((Time.now-summary[:after])/3600/24).round(1)} days ago) - #{summary[:before].strftime( "%Y-%m-%d %H:%M" )} (now)"
395
+ puts
396
+ puts "Activity Summary".underline.blue
397
+ summary[:type].keys.sort.each do |x|
398
+ printf "%-6s %s\n", summary[:type][x].count, x
399
+ end
400
+
401
+ puts
402
+ puts "Activity Breakdown".underline.blue
403
+ summary[:actors_activites].keys.sort.each do |x|
404
+ summary[:actors_activites][x].keys.select { |x| x}.sort.each do |type|
405
+ printf "%-6s %-25s %s\n", summary[:actors_activites][x][type].count, type.strip_email, x
406
+ end
407
+ end
408
+
409
+ puts
410
+ puts "New Tickets".underline.blue
411
+ (summary[:type]['bugtracking:openticket'] || []).each do |activity|
412
+ printf "%-15s %-100s\n", activity['actor_identifier'], activity['description'][0..100].gsub( /\n/, " " )
413
+ #puts activity['description'][0..100].gsub( /\n/, " " )
414
+ end
415
+
416
+ puts
417
+ puts "Closed Tickets".underline.blue
418
+ (summary[:type]['bugtracking:closedticket'] || []).each do |activity|
419
+ printf "%-15s %-100s\n", activity['actor_identifier'], activity['description'][0..100].gsub( /\n/, " " )
420
+ #puts activity['description'][0..100].gsub( /\n/, " " )
421
+ end
422
+
423
+ puts
424
+ puts "Active Tickets".underline.blue
425
+ summary[:type].keys.select do |x|
426
+ x =~ /bugtracking/
427
+ end.collect do |x|
428
+ summary[:type][x].collect do |a|
429
+ a['description']
430
+ end
431
+ end.flatten.sort.uniq.each do |x|
432
+ puts x[0..100].gsub( /\n/, " " ) unless x =~ /^\[Changeset\]/
433
+ end
434
+
435
+ puts
436
+ puts "Commits".underline.blue
437
+ (summary[:type]['sourcecontrol:commit'] || []).each do |x|
438
+ printf "%-30s %s\n", x['actor_identifier'].strip_email, x['description'][0..100].gsub( /\n/, " " )
439
+ end
440
+ end
441
+
442
+ desc "report NAME", "Report for an individual project"
443
+ option :lastweek
444
+ def report(name)
445
+ info name
446
+ activity name
447
+ end
448
+
449
+ desc "report_dump", "Write out weekly reports"
450
+ option :lastweek
451
+ def report_dump
452
+ puts "Loading projects"
453
+
454
+ system "mkdir -p /tmp/juice_reports"
455
+ client.projects.each do |project|
456
+ File.open( "/tmp/juice_reports/#{project['name']}.txt", "w" ) do |out|
457
+ puts "Running report for #{project['name']}"
458
+ $stdout = out
459
+ info project['name']
460
+ activities project['name']
461
+ $stdout = STDOUT
462
+ end
463
+ end
464
+ end
465
+
466
+ no_commands do
467
+ def client
468
+ @client ||= Blend::Client.juice_client
469
+ end
470
+
471
+ def hipchat_client
472
+ Blend::Client.hipchat_client
473
+ end
474
+
475
+ def github_client
476
+ Blend::Client.github_client
477
+ end
478
+
479
+ def heroku_client
480
+ Blend::Client.heroku_client
481
+ end
482
+
483
+ def project_id_from_name( name )
484
+ client.project_id_from_name( name )
485
+ end
486
+
487
+ def set( s )
488
+ !s.nil? && s != ""
489
+ end
490
+ end
491
+ end
492
+ end
493
+ end